且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在API 29或Android Q中使用DownloadManager下载文件?

更新时间:2023-01-23 12:53:22

我只是使用以下方法解决了:

I solved just by using:

setDestinationInExternalFilesDir(context, relativePath, filename);

代替:

setDestinationInExternalPublicDir(relativePath, filename);

我的相对路径是:

Environment.getExternalStorageDirectory().getPath() + "MyExternalStorageAppPath"

我的清单中也有

android:requestLegacyExternalStorage="true"

要使用旧版存储管理(共享存储),而不是Android 10及更高版本中使用的新存储管理(范围存储).

To use Legacy storage management (Shared Storage) instead of new storage management (Scoped Storage) used from Android 10 and above.

请记住,通过使用"setDestinationInExternalFilesDir"文件将下载到专用于您的应用的外部存储器中,因此:"external/Android/data/your_app_name/path_you_used_on_function".如果要将其下载到其他位置,则需要在使用Input&输出流.要使用Android 10或更高版本的另一个应用打开文件,您必须使用FileProvider.

Remember that by using "setDestinationInExternalFilesDir" files will be download to the external memory dedicated to your app, so: "external/Android/data/your_app_name/path_you_used_on_function". If you want to download it to another place you need to move It after you downloaded It by using Input & Output streams. To open the file with another app in Android version 10 or above you must use FileProvider.

如果有人需要,这是移动代码(移动而不是复制.因此原始文件将被删除.如果要复制文件而不删除文件,则删除"source.delete();").源文件)从一个位置到另一个位置的文件:

If someone need it, this is the code to move (move, not copy. So the original file will be deleted. Remove "source.delete();" if you want to copy the file and not delete the source file) a file from one location to another:

public static boolean moveFile(File source, String destPath){
        if(source.exists()){
            File dest = new File(destPath);
            checkMakeDirs(dest.getParent());
            try (FileInputStream fis = new FileInputStream(source);
                 FileOutputStream fos = new FileOutputStream(dest)){
                if(!dest.exists()){
                    dest.createNewFile();
                }
                writeToOutputStream(fis, fos);
                source.delete();
                return true;
            } catch (IOException ioE){
                Log.e(TAG, ioE.getMessage());
            }
        }
        return false;
    }

private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException {
        byte[] buffer = new byte[1024];
        int length;
        if (is != null) {
            while ((length = is.read(buffer)) > 0x0) {
                os.write(buffer, 0x0, length);
            }
        }
        os.flush();
    }

用法(源"是您需要移动的文件,路径"是目标):

Usage ("source" is the File you need to move, "path" is the destination):

if(FilesUtils.moveFile(source, path)) {
     // Success Moving File, do what you need with it
}

DownloadManager完成时的广播接收器:

private static class DownloadFileReceiver extends BroadcastReceiver {

        private DownloadManager mDownloadManager;
        private String mPath;

        private DownloadFileReceiver(DownloadManager dManager, String path){
            mDownloadManager = dManager;
            mPath = path;
        }

        /** Override BroadcastReceiver Methods **/
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
                Bundle extras = intent.getExtras();
                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID));
                Cursor c = mDownloadManager.query(q);
                if (c.moveToFirst()) {
                    int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
                    if (status == DownloadManager.STATUS_SUCCESSFUL) {
                        String fullPath = null; File source = null;
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            fullPath = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                            source = new File(Uri.parse(fullPath).getPath());
                        } else {
                            fullPath = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                            source = new File(fullPath);
                        }
                    }
                }
                c.close();
            }
            Objects.requireNonNull(context).unregisterReceiver(this);
        }
    }

将其注册到DownloadManager实例:

context.registerReceiver(new DownloadFileReceiver(downloadManager, path),
                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

checkMakeDirs(检查目录是否存在或是否可以成功创建目录)和makeDirs(仅在不进行检查的情况下进行创建)代码:

public static boolean checkMakeDirs(String dirPath){
        try {
            File dir = new File(dirPath);
            return dir.exists() || dir.mkdirs();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
        return false;
    }

    public static void makeDirs(String dirPath){
        try {
            File dir = new File(dirPath);
            if(!dir.exists()){
                dir.mkdirs();
            }
        } catch (Exception e){
            Log.e(TAG, e.getMessage());
        }
    }