将内容:// URI转换为Android 4.4中的实际path

我尝试了一个解决scheme(见下文),除了在Android 4.4中对startActivityForResult()的调用会产生一个标题为“Open from”的活动,其中包含“Recent”,“Images”,“Downloads”以及多个应用程序从中挑选。 当我select“Images”并尝试parsing返回的内容URI(使用下面的代码)时,对cursor.getString()的调用返回null。 如果我使用Gallery应用程序select完全相同的文件, cursor.getString()将返回一个文件path。 我只testing了API级别16和19.一切都如预期在16年。至19,去,我不得不select图库或其他应用程序或它不工作。

 private String getRealPathFromURI(Context context, Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = context.getContentResolver().query(contentUri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String path = cursor.getString(column_index); return path; } finally { if (cursor != null) { cursor.close(); } } } 

这将从MediaProvider,DownloadsProvider和ExternalStorageProvider获取文件path,同时回到您提到的非官方ContentProvider方法。

  /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and * other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @author paulburke */ public static String getPath(final Context context, final Uri uri) { 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]; } // TODO handle non-primary volumes } // 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 getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @param selection (Optional) Filter used in the query. * @param selectionArgs (Optional) Selection arguments used in the query. * @return The value of the _data column, which is typically a file path. */ 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 column_index = cursor.getColumnIndexOrThrow(column); return cursor.getString(column_index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * @param uri The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. */ public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is DownloadsProvider. */ public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is MediaProvider. */ public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } 

源 aFileChooser

将内容:// URI转换为Android 4.4中的实际path

在任何Android版本上都没有可靠的方法来做到这一点。 content:// Uri不必在文件系统上表示文件,更不用说可以访问的文件了。

Android 4.4的改变提供的存储框架只是增加你将遇到的content://的频率content:// Uri值。

如果你得到一个content:// Uri ,请使用ContentResolveropenInputStream()openOutputStream()方法来使用它。

我也一直在面对这个问题,但就我而言,我想要做的是指定一个具体的Uri到画廊,所以我可以稍后使用裁剪。 看起来,在KitKat的新文档浏览器中,除非您在抽屉式导航栏中selectGalery,否则我们不能再这样做了,就像您所说,直接从那里打开图像或文件。

在Uri的情况下,您仍然可以从文档浏览器中打开时检索path。

  Intent dataIntent= new Intent(Intent.ACTION_GET_CONTENT); dataIntent.setType("image/*"); //Or whatever type you need 

然后在onActivityResult中:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ACTIVITY_SELECT_IMAGE && resultCode == RESULT_OK) { myUri = data.getData(); String path = myUri.getPath(); openPath(myUri); } } 

如果您需要使用该path打开文件,则只需使用内容parsing器:

 public void openPath(Uri uri){ InputStream is = null; try { is = getContentResolver().openInputStream(uri); //Convert your stream to data here is.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 

它是在Google API中引入的。 你可以试试这个:

 private Bitmap getBitmapFromUri(Uri uri) throws IOException { ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r"); FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); parcelFileDescriptor.close(); return image; } 

从Uri获取文件path: –我创build了一个Util类,它将获得存储访问框架文档的path,以及MediaStore和其他基于文件的ContentProviders的_data字段。

ConvertUriToFilePath: – http://www.codesend.com/view/f4668a29860235dd1b66eb419c5a58b5/

示例代码:

 // Just call this function of ConvertUriToFilePath class and it will return full path of file URI. String actualFilepath= ConvertUriToFilePath.getPathFromURI(activity,tempUri); 

如果你真的需要一个文件path。 首先,使用ContentResolver获取数据。 然后,您可以将数据保存到临时文件并使用该path。

(我不得不在一个函数参数中使用带有File对象的库。)

感谢@FireBear,我现在修改了答案,将获得媒体文件的path

String filePath = saveBitmap(activity,getBitmapFromUri(imageUri),“tmpFile”)。getPath();

 private Bitmap getBitmapFromUri(Context context, Uri uri) throws IOException { ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r"); FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); parcelFileDescriptor.close(); return image; } private File saveBitmap(Context context, Bitmap bitmap, String name) { File filesDir = context.getFilesDir(); File imageFile = new File(filesDir, name + ".jpg"); OutputStream os; try { os = new FileOutputStream(imageFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); os.flush(); os.close(); } catch (Exception e) { //Log.e(getClass().getSimpleName(), "Error writing bitmap", e); } return imageFile; }