【问题标题】:Get a Content URI from a File URI?从文件 URI 获取内容 URI?
【发布时间】:2014-06-06 02:53:08
【问题描述】:

我正在使用DownloadManager 将图像下载到系统的图库,然后在广播接收器中(一旦下载成功)使用 Intent 将图像设置为壁纸。

一切正常,但最近在 4.4 上,我开始在照片/Google+ 应用中遇到异常,因为它需要的是内容 URI,而不是文件 URI。

所以我的问题是,是否有人知道如何将完整的文件路径/URI (file://) 转换为内容样式 URI (content://)?

抱歉缺少源代码,我远离有源代码的计算机,但我希望没有它的问题有意义,从完整路径获取内容样式 uri。

编辑:

图像被复制到系统的图库或媒体库中,而不是保存在我的应用程序内部存储中。

这是我要转换的示例:

file:///storage/emulated/0/Pictures/Rockstar/image.jpg

到

content://media/internal/images/media/445

编辑 2:

这是我从 Google+ 应用中得到的错误:

04-21 10:50:35.090: E/AndroidRuntime(7220): FATAL EXCEPTION: main
04-21 10:50:35.090: E/AndroidRuntime(7220): Process: com.google.android.apps.plus, PID: 7220
04-21 10:50:35.090: E/AndroidRuntime(7220): java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.plus/com.google.android.apps.photos.phone.SetWallpaperActivity}:  
java.lang.IllegalArgumentException: Image URI must be of the content scheme type

这是我用来让用户设置壁纸的代码:

String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
Uri u = Uri.parse(uriString);
Intent wall_intent =  new Intent(Intent.ACTION_ATTACH_DATA);
wall_intent.setDataAndType(u, "image/*");
wall_intent.putExtra("mimeType", "image/*");
Intent chooserIntent = Intent.createChooser(wall_intent,
    "Set As");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);      
try {
    context.startActivity(chooserIntent);
} 

uriString 在哪里:

file:///storage/emulated/0/Pictures/Rockstar/image.jpg

【问题讨论】:

    标签: android


    【解决方案1】:

    所以我的问题是,是否有人知道如何将完整的文件路径/URI (file://) 转换为内容样式 URI (content://)?

    实现ContentProvider。 FileProvider 为提供本地文件提供了开箱即用的解决方案。

    【讨论】:

    • 我正在下载图像(使用下载管理器)到系统的媒体库,而不是将文件存储在我的应用程序的内部存储中。那么在这种情况下,ContentProvider 会是一条路吗?我有(例如)file:///sdcard/media/images/myimage.png 我想转换为: content://media/internal/images/media/445
    【解决方案2】:

    我不确定您用于设置壁纸的技术,但最简单的方法可能是使用不需要任何 URI 的 WallpaperManager.setStream()。

    另请注意,文件 URI 仅在文件可公开访问的情况下在应用之间有效,因此内容 URI 是更通用的解决方案。

    使用内容 URI 意味着 ContentProvider 将提供文件。哪一个取决于您的文件所在的位置。

    如果您的应用对文件具有直接读取权限,您可以通过使用支持库的 FileProvider 类在您的应用中实现内容提供程序,但仅当文件位于在您应用的私有数据存储中。

    如果将图像添加到系统媒体库,您可能应该使用 MediaStore 提供的 URI。

    【讨论】:

    • 是的,文件已下载到系统的媒体库(使用下载管理器),但我可以通过 DownloadManager.COLUMN_LOCAL_URI 列在广播接收器中访问的所有内容都是文件的完整路径.如何根据该完整路径从 MediaStore 获取 URI?我还使用了一个意图和一个 URI,以便图库或照片应用程序可以裁剪图像。
    • 我自己没试过,但是下载完成后看看DownloadManager.COLUMN_MEDIAPROVIDER_URI列,看看是否包含内容URI。如果它看起来太复杂,您仍然可以实现自己的内容提供程序,但对我来说感觉就像一个 hack。
    【解决方案3】:

    我能够弄清楚。这是在这里找到的代码的组合:Converting android image URI 和下载后扫描媒体文件。

    所以在文件下载完成后,我得到路径并执行以下操作:

    String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
    
    //Update the System
    Uri u = Uri.parse(uriString);                       
    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, u));
    
    //Get the abs path using a file, this is important          
    File wallpaper_file = new File(u.getPath());
    Uri contentURI = getImageContentUri(context, wallpaper_file.getAbsolutePath());
    

    由于某种原因,启动媒体扫描仪、更新文件和获取绝对路径很重要,我不确定为什么,但我不能再花时间在这上面了!

    从文件 URI 转换为内容 URI 的方法如下(取自链接的 StackOver 流帖子:

    public static Uri getImageContentUri(Context context, String absPath) {
        Log.v(TAG, "getImageContentUri: " + absPath);
    
        Cursor cursor = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            , new String[] { MediaStore.Images.Media._ID }
            , MediaStore.Images.Media.DATA + "=? "
            , new String[] { absPath }, null);
    
        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
            return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , Integer.toString(id));
    
        } else if (!absPath.isEmpty()) {
             ContentValues values = new ContentValues();
             values.put(MediaStore.Images.Media.DATA, absPath);
             return context.getContentResolver().insert(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } else {
            return null;
        }
    }
    

    也许这会对将来的某人有所帮助。

    【讨论】:

    • 这里的c是什么?我的意思是这个光标的定义是什么。
    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    • 2014-07-31
    • 2012-08-15
    相关资源
    最近更新 更多