其他
Android就想下载个文件到SD卡,怎就这么难?快把代码拿走吧
本文作者
作者:Newki
链接:
https://juejin.cn/post/7383311950175272998
本文由作者授权发布。
前言
那么我们应该如何实现一个简单的下载文件到 SD 卡呢?
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String downloadPath = downloadDir.getAbsolutePath();
MyOkhttpUtil.okHttpDownloadFile("http://www.baidu.com/income-eligibility-criteria.pdf",
new CallBackUtil.CallBackFile(downloadPath, fileName) {
@Override
public void onFailure(Call call, Exception e) {
LoadingDialogManager.get().dismissLoading();
YYLogUtils.e("downLoadMessageFile--onFailure");
ToastUtils.get().showFailText(CommUtils.getContext(), "File download failed");
}
@Override
public void onProgress(float progress, long total) {
super.onProgress(progress, total);
}
@Override
public void onResponse(Call call, File response) {
LoadingDialogManager.get().dismissLoading();
YYLogUtils.w("downLoadMessageFile--Success--path=" + response.getAbsolutePath());
ToastUtils.get().showSuccessText(CommUtils.getContext(),
"File download successful, save path: " + response.getAbsolutePath());
}
});
PermissionEngine.get().requestPermission(activity, new PermissionEngine.OnSuccessCallback() {
@Override
public void onSuccess() {
}
}, Manifest.permission_group.STORAGE);
PermissionEngine.get().requestPermission(activity, new PermissionEngine.OnSuccessCallback() {
@Override
public void onSuccess() {
}
},Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);
其他的方式我们不提,因为今天的主题只是下载写入文件而已,跟多媒体的读取权限没关系,我们只需要申请写入文件的权限就可以兼容安卓10以下的版本。
PermissionEngine.get().requestPermission(activity, new PermissionEngine.OnSuccessCallback() {
@Override
public void onSuccess() {
//SD卡权限申请成功之后再次尝试
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// 获取SD卡中Download目录的路径
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String downloadPath = downloadDir.getAbsolutePath();
YYLogUtils.w("准备下的路径为:" + downloadPath + fileName);
LoadingDialogManager.get().showLoading(activity);
MyOkhttpUtil.okHttpDownloadFile(downloadUrl, new CallBackUtil.CallBackFile(downloadPath, fileName) {
@Override
public void onFailure(Call call, Exception e) {
LoadingDialogManager.get().dismissLoading();
YYLogUtils.e("downLoadMessageFile--onFailure");
ToastUtils.get().showFailText(CommUtils.getContext(), "File download failed");
}
@Override
public void onProgress(float progress, long total) {
super.onProgress(progress, total);
}
@Override
public void onResponse(Call call, File response) {
LoadingDialogManager.get().dismissLoading();
YYLogUtils.w("downLoadMessageFile--Success--path=" + response.getAbsolutePath());
ToastUtils.get().showSuccessText(CommUtils.getContext(),
"File download successful, save path: " + response.getAbsolutePath());
}
});
} else {
YYLogUtils.e("SD card not available or not writable.");
}
}
}, Manifest.permission.WRITE_EXTERNAL_STORAGE);
还初步测试了 Android 11,12,14等机型都没问题。
private void downloadFile(DocumentFile selectedDir, String fileName) {
String url = "http://example.com/file.pdf";
File parent = new File(selectedDir.getPath());
DocumentFile documentFile = DocumentFile.fromFile(parent);
DocumentFile subDocumentFile = documentFile.createFile("application/pdf", fileName);
Uri uri = subDocumentFile.getUri();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 处理下载失败的情况
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
OutputStream outputStream = null;
try {
outputStream = getContentResolver().openOutputStream(uri);
if (outputStream != null) {
copyInputStreamToOutputStream(inputStream, outputStream);
} else {
// 处理输出流为空的情况
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
});
}
private void copyInputStreamToOutputStream(InputStream inputStream, OutputStream outputStream) throws IOException {
byte[] buffer = new byte[4096];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
}
咦?为什么要用 DocumentFile ?直接用 File 不行吗 ?还真不行,有兼容性问题,具体可以看看我早期的文章【Android操作文件也太难了趴,File vs DocumentFile 的异同】。这是我刚接触博客写的文章,现在看来很粗糙了,大家见谅。
https://juejin.cn/post/7211422882253537339#heading-2
总结来说就是 Android10 以上的系统是无法使用 File 来写入的,除了一些特殊文件夹才能写入。Android10 以上的设备想写入自定义文件夹中的文件,还是推荐使用 DocumentFile 的方案。
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
activity.startActivityForResult(intent, 1027);
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1027 && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri treeUri = data.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
if (pickedDir != null) {
// 使用pickedDir来下载文件
Uri uri = pickedDir.getUri();
String name = pickedDir.getName();
boolean canRead = pickedDir.canRead();
boolean canWrite = pickedDir.canWrite();
YYLogUtils.w("uri:" + uri + " name:" + name + " canRead:" + canRead + " canWrite:" + canWrite);
}
}
}
}
有了 Uri 了还需要我再说了吗,把上面的代码套过来,直接输入流和输出流对接就保存文件了。
本文简单的介绍了 Android 系统权限收紧的介绍,并且对于如何写入文件方面做了几种适配案的探讨。
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!