MediaStore API无法获取在应用“清除数据”之前已创建的文件夹。

3
为了支持Android 11存储,我已经成功实现了Scoped Storage - MediaStore API。然而,我遇到了一个场景,不确定如何解决。场景是:当应用程序第一次启动时,我们已经在Documents文件夹下创建了文件夹,并且能够读写该文件夹中的文件,而无需创建任何重复的文件夹。然而,如果我清除数据并重新登录应用程序,则无法获取已创建的文件夹,并且每次都会创建一个新的带有重复名称后缀为(2),(3)等的文件夹。
请查看我尝试过的代码以及截图。
         File folder = null;
         String folderName = "Duration";
         if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
            Uri contentUri = MediaStore.Files.getContentUri("external");
            String filePath = FileUtils.readFileExternalStorage(contentUri,context,folderName).getPath();
            if (!TextUtils.isEmpty(filePath) && FileUtils.isFileExisting(filePath)) {
                folder = new File(filePath);
            } else {
                Uri uri = FileUtils.createFileExternalStorage(contentUri,context,folderName),Environment.DIRECTORY_DOCUMENTS);
                Commons.print("URI "+uri.getPath());
                folder = new File(FileUtils.getPath(context,uri));
            }
            if (!folder.exists()) {
                folder.mkdirs();
            }
      
        } else {
         
            folder = getStorageDir(folderName);
            bmodel.deleteFiles(getStorageDir(folderName) + "/", filename);
        }

        File file = new File(folder, filename );
        if(file.exists()) {
            file.delete();
        }
        if (SynchronizationHelper.bcpJSONData != null) {
            FileOutputStream outputStream;
            try {
                Commons.print("FilePath " + file.getPath());

                outputStream = new FileOutputStream(file);//context.openFileOutput(filename, Context.MODE_PRIVATE);
                outputStream.write(SynchronizationHelper.bcpJSONData.getBytes());
                outputStream.close();
                outputStream = null;
                SynchronizationHelper.bcpJSONData = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

这是 FileUtils 类:

    @RequiresApi(api = Build.VERSION_CODES.Q)
public static File readFileExternalStorage(Uri contentUri, Context context, String filename) {

    final String selection = MediaStore.Files.FileColumns.DISPLAY_NAME + "=?";
    final String[] selectionArgs = new String[] {filename};
    return new File(getDataColumn(context,contentUri,selection,selectionArgs));
}

    @RequiresApi(api = Build.VERSION_CODES.Q)
public static Uri createFileExternalStorage(Uri contentUri, Context context, String filename, String folder) {

    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename);
    values.put(MediaStore.MediaColumns.RELATIVE_PATH, folder);
    return context.getContentResolver().insert(contentUri, values);
}

    public static String getDataColumn(Context context, Uri uri,
                                   String selection, String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = { column };

    try {
        cursor = context.getContentResolver().query(uri, projection,
                selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return "";
}

    @TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {

    // check here to KITKAT or new version
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {

        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/"
                        + split[1];
            }
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"),
                    Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] { split[1] };

            return getDataColumn(context, contentUri, selection,
                    selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return "";
}

清除应用程序数据后,在每个实例中,此方法getDataColumn()返回空字符串"",在调试期间我发现try块内的游标未从中获取任何内容。
请从文件管理器中查找下面的文档文件夹:Please find the Document Folder below from File Manager
1个回答

0

嗯,首先你应该考虑两件事情。

1. 如果文件夹已经存在,则不要创建

2. 使用不同的代码从文件夹中加载媒体

所以,这里有一点帮助。

1. 检查目录是否存在。

if (!file.exists()) {
                    createFolder();
                }

然后

2. 以不同方式加载媒体

private ArrayList<Media> loadMedia(String directory_name) {
        mediaList = new ArrayList<>();
        String selection;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            selection = MediaStore.MediaColumns.RELATIVE_PATH + " LIKE ? ";
        } else {
            selection = MediaStore.Images.Media.DATA + " LIKE ? ";
        }

        String[] selectionArgs = new String[]{directory_name};

        Cursor cursor = getContentResolver().query(
                MediaStore.Files.getContentUri("external"),
                null,
                selection,
                selectionArgs,
                MediaStore.Video.Media.DATE_TAKEN + " DESC");
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
                do {
                    int imageCol = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                    long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    long date = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
                    String pathId = cursor.getString(imageCol);
                    Uri uri = Uri.parse(pathId);
                    Uri contentUri;
                    if (uri.toString().endsWith(".mp4")) {
                        contentUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
                    } else {
                        contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
                    }
                    Media media = new Media();
                    media.setPath(path);
                    media.setMediaStoreUri(contentUri);
                    media.setUri(uri);
                    media.setAlbumName(new File(path).getParent());
                    mediaList.add(media);
                }
                while (cursor.moveToNext());
                cursor.close();
            }
        }
        return mediaList;
    }

这段代码在所有设备上都能完美运行,包括 Android 10 及以上版本。试试看吧。

祝一切顺利!


它并没有解决问题。 - Sajeel
你的设备安卓系统版本是多少? - Dev4Life
安卓10,我还没有将“requestlegacyexternalstorage”设置为true。 - Sajeel
不需要使用MediaStore API。你能打印出游标中的总行数日志吗?它显示了多少行? - Dev4Life
每当我卸载应用程序或清除数据时,文件就无法再访问了。例如,在清除数据后,我只能访问那些在此之后创建的文件。我在清除数据之前创建的文件仍然存在,但无法再访问。 - Sajeel
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接