如何在删除照片后刷新Android的MediaStore

7

问题:如何使媒体库刷新其已删除文件的条目?

在从外部存储中的代码中删除照片后,我仍然可以在图库中看到已删除照片的空白照片槽。

似乎图库反映了媒体库,并且在重新启动手机或通常情况下重新扫描媒体之前,已删除的照片在媒体库中被发现。

尝试扫描已删除的文件 没有 帮助扫描已删除的文件(仅适用于新文件或现有文件):MediaScannerConnection.scanFile(Application.get(),new String [] {file.getPath()},null,null)(我也尝试扫描父文件夹)。

还尝试了ACTION_MEDIA_SCANNER_SCAN_FILE,但无济于事。示例:Application.get().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)))

发送广播接收器以重新扫描整个外部存储器(从而刷新媒体库)解决了问题:Application.get().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(Environment.getExternalStorageDirectory())))

但是,截至4.4,Android在尝试手动发送ACTION_MEDIA_MOUNTED系统广播时会抛出安全异常。请参见@CommonsWare的帖子:http://commonsware.com/blog/2013/11/06/android-4p4-permission-regressions.html

因此,在删除文件(/照片/视频等)时,我陷入了无法刷新媒体库的困境。

4个回答

4

我在Nexus 10上的 Android 4.4 版本中找到了下面这个对我有用的解决方案。

// request scan
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, SELECT_PICTURE);
Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
scanIntent.setData(Uri.fromFile(refreshFile));
sendBroadcast(scanIntent);

"refreshFile" 是我从字符串 "fPath" 中获取并转换为文件的已删除文件。

String filePath = fPath;        
File refreshFile = new File(filePath);

“ACTION_GET_CONTENT”的目的是什么? - AlikElzin-kilaka
就像我说的那样... 我发现了这个。我对所有这些都很新,并不会自称为专家。 我只知道它对我起作用了。 - Sobo
你编写的代码还使用了ACTION_GET_CONTENT动作启动了一个活动。如果它是解决方案的一部分,那么它本身就有问题。 - AlikElzin-kilaka
我尝试了ACTION_MEDIA_SCANNER_SCAN_FILE,但在SGS4上没有起作用。 - AlikElzin-kilaka
3
Kilaka,这不是我的代码,就像我说的那样,我只是找到了它!并且它对我有效!所以因为它对你不起作用而抹黑我的声誉......这样就不用试图帮助别人了。 - Sobo

1

我遇到了同样的问题。我编写了以下代码,并且它适用于从棒棒糖版本到奥利奥版本的所有Android系统。此外,我调用了mediastore.scanfile()方法以确保MediaStore已更新。下面是添加的代码 - 未来您可能不想使用"delete()"方法,因为scanfile()可能更全面。但是,如果您想支持旧手机,则删除()可能更安全。

    // fileID == MediaStore.Images.Media._ID; for the file when you get the file from the content 
// resolver
public static boolean deleteCREntryForFilePath(Context context, String filePath, long fileID) {
    boolean         fDeleted       = false;
    ContentResolver cr             = context.getContentResolver();
    int             rowsDeleted    = 0;
    Uri             imageURI       = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    String          deleteStr      = MediaStore.Images.Media._ID + "=" + fileID;

    MediaScannerConnection.scanFile(context, new String[]{filePath}, null, null);

    // Remove entry from database
    rowsDeleted = context.getContentResolver().delete(
            imageURI, deleteStr, null);
    if (rowsDeleted > 0)
        fDeleted = true;
    return(fDeleted);
}

这里是获取文件ID的代码(函数名为getfileId())。它适用于不同类型的文件。您不能直接编译此代码,因为它使用了内部对象类型,但您应该很容易地将其转换为通用用途。

public static String[] getCombinedEntityColumns(Constants.DELASHARE_OBJECT_TYPES objType) {
    String[] entityColumns = new String[5];

    switch (objType) {
        case DELASHARE_OBJECT_PICTURE:
        case DELASHARE_OBJECT_MUSIC:
        case DELASHARE_OBJECT_VIDEO: {

            entityColumns[0] = MediaStore.Images.Media.DISPLAY_NAME;
            entityColumns[1] = MediaStore.Images.Media.DATA;
            entityColumns[2] = MediaStore.Images.Media._ID;
            entityColumns[3] = MediaStore.Images.Media.DATE_ADDED;
            //entityColumns[3] = MediaStore.Images.Media.DATE_TAKEN;
            entityColumns[4] = MediaStore.Images.Media.SIZE;
            break;
        }
        case DELASHARE_OBJECT_APK:
        case DELASHARE_OBJECT_DOCUMENT:
        case DELASHARE_OBJECT_DOWNLOAD:
        case DELASHARE_OBJECT_SEARCH_RESULTS:
        default: {
            entityColumns[0] = MediaStore.Files.FileColumns.DISPLAY_NAME;
            entityColumns[1] = MediaStore.Files.FileColumns.DATA;
            entityColumns[2] = MediaStore.Files.FileColumns._ID;
            entityColumns[3] = MediaStore.Files.FileColumns.DATE_MODIFIED;
            entityColumns[4] = MediaStore.Files.FileColumns.SIZE;
            break;
        }
    }
    return (entityColumns);
}

public static Uri getCategoryUri(Constants.DELASHARE_OBJECT_TYPES categoryObjType) {
    Uri  objUri = null;

    switch(categoryObjType) {
        case DELASHARE_OBJECT_PICTURE:
            objUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            break;
        case DELASHARE_OBJECT_VIDEO:
            objUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            break;
        case DELASHARE_OBJECT_MUSIC:
            objUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            break;
        case DELASHARE_OBJECT_DOWNLOAD: {
            File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
            objUri = Uri.fromFile( downloadDir);
            //objUri = MediaStore.Files.getContentUri("external");
            break;
        }
        case DELASHARE_OBJECT_APK:
        case DELASHARE_OBJECT_DOCUMENT:
        case DELASHARE_OBJECT_SEARCH_RESULTS:
        default:
            objUri = MediaStore.Files.getContentUri("external");
            break;

    }

    return(objUri);
}

public  static long getFileId(Context context, String dirPath, String filePath, String fileName, Constants.DELASHARE_OBJECT_TYPES objType) {
    boolean fIDFound = false;
    long    id       = 0;
    if (!fIDFound) {
        String          sortOrder      = null;
        String[]        entityColumns  = getCombinedEntityColumns(objType);
        Uri             categoryUri    = getCategoryUri(objType);
        String          selection      = null;
        String[]        selectionArgs  = new String[]{Constants.DELA_PERCENT_STR + dirPath};
        ContentResolver cr             = context.getContentResolver();
        Cursor cursor = null;

        switch (objType) {
            case DELASHARE_OBJECT_PICTURE:
                selection = MediaStore.Images.Media.DATA + " LIKE ?";
                break;
            case DELASHARE_OBJECT_VIDEO:
                selection = MediaStore.Video.Media.DATA + " LIKE ?";
                break;
            case DELASHARE_OBJECT_DOCUMENT:
            default:
                selection = MediaStore.Files.FileColumns.DATA + " LIKE  ?";
                break;
        }
        cursor = cr.query(
                categoryUri,
                entityColumns,
                selection,
                selectionArgs,
                sortOrder);

        if (cursor != null && cursor.moveToFirst()) {
            id = cursor.getLong(cursor.getColumnIndex(entityColumns[2]));

            if (id != 0) {
                fIDFound = true;
            }
        }
        if (cursor != null) {
            cursor.close();
            cursor = null;
        }
    }
    return(id);

}

我们如何获取文件ID? - Daxesh Vekariya
我已经复制了获取文件ID的代码。它相当复杂,但适用于各种类型的文件。希望这可以帮到你。 - Raju
没有这样的方法MediaStore.scanfile() - user924
可使用的API是MediaScannerConnection.scanFile()。您可以查看以下网站以了解此API的工作原理。https://developer.android.com/reference/android/media/MediaScannerConnection - Raju

0

尝试

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

将此内容添加到你的清单文件中:
<intent-filter>
      <action android:name="android.intent.action.MEDIA_MOUNTED" />
      <data android:scheme="file" /> 
</intent-filter>

它的最高API版本是18(果冻豆),你怎么能在2016年回答它呢?这是相当老的API,使用更高的API将会抛出异常,现在只有系统应用程序可以执行此操作。另外,这里的<intent-filter>是什么意思,它不是必需的,也没有任何作用。 - user924

0

我曾经和你一样有同样的问题,现在在4.4中sendBroadcast方法被禁止了,但是我在这里找到了一个好的解决方案,使用Media Store内容提供程序:https://dev59.com/X2gv5IYBdhLWcg3wSe0f#20780472

我在Android 4.4上测试过它,效果很好。我认为这是一个可靠的方法。


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