【问题标题】:How to refresh Android's MediaStore upon photo deletion删除照片后如何刷新 Android 的 MediaStore
【发布时间】:2013-11-13 13:50:44
【问题描述】:

问题:如何让媒体商店刷新其已删除文件的条目?

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

画廊似乎反映了媒体存储,并且删除的照片在媒体存储中找到,直到手机重新启动或通常 - 直到重新扫描媒体。

尝试扫描已删除的文件有助于扫描已删除的文件(仅适用于新文件或现有文件):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

所以,我无法在文件(/照片/视频/等)删除时刷新媒体存储。

【问题讨论】:

    标签: android mediastore android-mediascanner


    【解决方案1】:

    我在 Nexus 10 上的 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”的目的是什么?
    • 正如我所说...我找到了这个。我对这一切都很陌生,并不自称是专家。我只知道它对我有用。
    • 您编写的代码还使用ACTION_GET_CONTENT 操作启动了一个活动。如果它是解决方案的一部分,它本身就是有问题的。
    • 我试过ACTION_MEDIA_SCANNER_SCAN_FILE,但没有用(无论如何在 SGS4 上)。
    • Kilaka,这不是我的代码。就像我说的。我找到了!!它适用于我!因此,您降低了我的声誉,因为它对您不起作用……尝试帮助人们真是太好了。
    【解决方案2】:

    我有同样的问题。我编写了以下代码,它适用于从棒棒糖到奥利奥的所有版本。我还调用了 mediastore.scanfile() 方法来确保 MediaStore 已更新。添加下面的代码 - 您将来可能不想使用“delete()”方法,因为 scanfile() 可能是全面的。但是,如果您想支持旧手机,那么 delete() 可能会更安全。

        // 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?
    • 我已经粘贴了获取上面文件id的代码。它非常复杂,适用于各种文件。希望这会有所帮助。
    • 没有这种方法MediaStore.scanfile()
    • 要使用的 API 是 MediaScannerConnection.scanFile() 您可以查看以下站点以了解此 API 的工作原理。 developer.android.com/reference/android/media/…
    【解决方案3】:

    现在我和你有同样的问题,sendBroadcast 方法在 4.4 中被禁止,并在这里使用 Media Store 内容提供程序找到了一个很好的解决方案:https://stackoverflow.com/a/20780472/1060805

    我在 Android 4.4 上对其进行了测试,它运行良好。我认为这是一种可靠的方法。

    【讨论】:

      【解决方案4】:

      试试

      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 (Jelly Bean) 的最大值,2016 年你怎么回答?这是相当老的 API,在更高的 API 上你会得到异常,现在只有系统应用程序可以做到。还有 &lt;intent-filter&gt; 在这里的意思,它不是必需的,它什么也不做
      猜你喜欢
      • 2017-05-03
      • 2011-03-19
      • 2019-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多