Android 4.4(KitKat)上的Android Gallery为Intent.ACTION_GET_CONTENT返回不同的URI。

217 人关注

在KitKat之前(或在新的Gallery之前), Intent.ACTION_GET_CONTENT 返回的URI是这样的

content://media/external/images/media/3951。

使用 ContentResolver 并查询 MediaStore.Images.Media.DATA 返回文件的URL。

然而,在KitKat中,画廊返回一个URI(通过 "Last"),像这样。

content://com.android.providers.media.documents/image:3951

我如何处理这个问题?

5 个评论
我将找到不需要直接访问文件的内容的使用方法。例如, Uri 应该可以通过 ContentResolver 作为一个流打开。长期以来,我一直对那些假定 content:// 的应用程序感到紧张。代表一个文件的 Uri 总是可以被转换为 File
@CommonsWare,如果我想在sqlite db中保存一个图片路径,以便以后可以打开它,我应该保存URI还是绝对文件路径?
@CommonsWare 我同意你的紧张。 :-)但是,我需要能够将文件名(用于图像)传递给本地代码。一个解决方案是将使用 InputStream ContentResolver 上获得的数据复制到一个预先指定的地方,以便它有一个已知的文件名。然而,这在我看来是很浪费的。有其他建议吗?
@darrenp:嗯......,重写本地代码,以便通过JNI与 InputStream 一起工作?很遗憾,你没有那么多的选择。
这是很有用的信息。谢谢你的回答。我后来发现,我们现在是在内存中把图像传给C++,而不是通过一个文件,所以它我们现在可以使用 InputStream 而不是一个文件(这很好)。只有EXIF标签的读取稍微有点麻烦,需要 德鲁-诺克斯的图书馆 .非常感谢您的评论。
android
android-intent
android-gallery
android-contentresolver
Michael Greifeneder
Michael Greifeneder
发布于 2013-11-07
20 个回答
Paul Burke
Paul Burke
发布于 2014-02-05
已采纳
0 人赞同

这不需要特殊的权限,并且可以与存储访问框架以及非官方的 ContentProvider 模式(文件路径在 _data 字段)一起使用。

* 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 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 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 index = cursor.getColumnIndexOrThrow(column); return cursor.getString(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()); * @param uri The Uri to check. * @return Whether the Uri authority is Google Photos. public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority());

请看此方法的最新版本 here .

Josh
这在4.4版本的Nexus 5 Documents UI和其他一些使用标准图库应用程序的KitKat设备上运行得非常好,谢谢保罗!
谢谢你,我花了好长时间才在sdk上走到这一步!!。我的问题是,我的设备使用谷歌驱动器作为文件浏览器。如果文件在设备上,图像路径就很好,但如果文件在驱动器上,就无法打开。也许我只需要看看如何处理从谷歌硬盘上打开图片。问题是我的应用程序被写成使用文件路径,并使用不取样来获得图像......
@RuAware 当你选择一个Drive文件时,它给出了 Authority: com.google.android.apps.docs.storage Segments: [document, acc=1;doc=667] 。我不确定,但假设 doc 的值是 Uri 。ID,你可以对其进行查询。你很可能需要按照这里的 "在安卓上授权你的应用程序 "所详述的权限进行设置。 developers.google.com/drive/integrate-android-ui .如果你想明白了,请在此更新。
j__m
这绝对是可怕的!你不应该继续传播像这样 "欺骗 "的代码。它只支持你知道模式的源应用程序,而文档提供者模型的全部意义在于支持任意的源。
The _data wouldn't work when ContentProvider doesn't support it. It is recommended to follow @CommonsWare说明 而不再使用完整的文件路径,因为它可能是Dropbox云中的一个文件,而不是一个真正的文件。
finder
finder
发布于 2014-02-05
0 人赞同

Try this:

if (Build.VERSION.SDK_INT <19){
    Intent intent = new Intent(); 
    intent.setType("image/jpeg");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);
} else {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/jpeg");
    startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK) return;
    if (null == data) return;
    Uri originalUri = null;
    if (requestCode == GALLERY_INTENT_CALLED) {
        originalUri = data.getData();
    } else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {
        originalUri = data.getData();
        final int takeFlags = data.getFlags()
                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // Check for the freshest data.
        getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
    loadSomeStreamAsynkTask(originalUri);
  

@SuppressLint("NewApi")

采取可存活Uri许可的方式

你能不能详细说明一下KitKat的代码在做什么?这是否需要任何新的权限?前期的KitKat代码在KitKat上也对我有效。那么我为什么要为KitKat选择使用不同的代码呢?谢谢。
user65721
看来我们不能从新的SDK uri中获得路径。此外,谷歌在没有适当的文件和公告的情况下做出这样的改变也是很遗憾的。
你能解释一下如何获得文件的URL吗?我想获得sdcard中的真实路径。例如,如果是一张图片,我想获得这个路径/storage/sdcard0/DCIM/Camera/IMG_20131118_153817_119.jpg而不是文件Uri。
基于KitKat的文档( developer.android.com/about/versions/... )这可能不是OP需要的,除非他确实打算使用/编辑其他应用程序所拥有的文件。 如果OP想要一个副本或以与旧版本一致的方式做事情,@voytez的回答会更合适。
这对我来说并不奏效。我得到了以下异常(在4.4.2的股票上)。 E/AndroidRuntime(29204)。原因是:java.lang.SecurityException。要求的标志是0x1,但只允许0x0。
voytez
voytez
发布于 2014-02-05
0 人赞同

我也有同样的问题,尝试了上面的解决方案,但尽管它总体上是有效的,由于某些原因,我在一些图片的Uri内容提供者上得到了权限拒绝,尽管我已经正确添加了 android.permission.MANAGE_DOCUMENTS 的权限。

总之找到了其他的解决方案,那就是用.NET技术强制打开图片库而不是KITKAT文档视图。

// KITKAT
i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, CHOOSE_IMAGE_REQUEST);

然后加载图像。

Uri selectedImageURI = data.getData();
input = c.getContentResolver().openInputStream(selectedImageURI);
                BitmapFactory.decodeStream(input , null, opts);

替换代码3】可能需要你坚持权限标志等,一般来说经常会导致安全异常......

另一个解决方案是使用ACTION_GET_CONTENT结合c.getContentResolver().openInputStream(selectedImageURI),这在pre-KK和KK上都可以使用。Kitkat将使用新的文档视图,这个解决方案将适用于所有的应用程序,如照片、画廊、文件资源管理器、Dropbox、Google Drive等),但请记住,当使用这个解决方案时,你必须在你的onActivityResult()中创建图像,并存储在SD卡上,例如。在下一个应用程序启动时,从保存的URI中重新创建这个图像会在内容解析器上抛出安全异常,即使你按照谷歌API文档中的描述添加了权限标志(这就是我做一些测试时发生的情况)。

此外,Android开发者API指南建议。

ACTION_OPEN_DOCUMENT不是用来替代ACTION_GET_CONTENT的。你应该使用哪一个,取决于你的应用程序的需求 你的应用程序的需要。

如果你想让你的应用程序简单地读取/导入数据,请使用ACTION_GET_CONTENT。 数据。使用这种方法,应用程序会导入数据的副本,如 一个图像文件。

如果你想让你的应用程序有一个长期的、持久的访问文档的能力,请使用ACTION_OPEN_DOCUMENT。 使用ACTION_OPEN_DOCUMENT,如果你希望你的应用程序能够长期、持久地访问由文档 提供者所拥有的文件。一个例子是一个照片编辑应用程序,它让用户编辑 存储在文档提供者中的图片。

这个答案包含了符合我目的的正确信息。 在KitKat上有条件地使用ACTION_PICK和EXTERNAL_CONTENT_URI,可以通过ContentResolver获得图库中图片的元数据,就像在旧版本中仅仅使用ACTION_GET_CONTENT一样。
@voytez,通过你的信息返回的这个URI能否转换为图片的完整真实路径?
我相信是的,它应该像KitKat之前那样工作,因为这段代码强制打开图片库而不是KK文档视图。但如果你打算用它来创建图片,那么这个解决方案会更好,因为转换为真实路径是一个额外的不必要的步骤。
对我来说也是如此,而不是 Intent.ACTION_GET_CONTENT 。总之,我在新的 Intent 上保留了 Intent.createChooser() 的包装,以便让用户选择浏览的应用程序,并且如期工作。有人能看到这个解决方案的缺点吗?
对于任何想知道的人来说,这句话来自于 developer.android.com/guide/topics/providers/...
Michał Klimczak
Michał Klimczak
发布于 2014-02-05
0 人赞同

正如Commonsware所提到的,你不应该认为你通过 ContentResolver 得到的流是可以转换为文件的。

你真正应该做的是从 ContentProvider 中打开 InputStream ,然后从中创建一个位图。而且它在4.4和更早的版本上也可以使用,不需要反射。

    //cxt -> current context
    InputStream input;
    Bitmap bmp;
    try {
        input = cxt.getContentResolver().openInputStream(fileUri);
        bmp = BitmapFactory.decodeStream(input);
    } catch (FileNotFoundException e1) {

当然,如果你处理大图片,你应该用适当的inSampleSize来加载它们。http://developer.android.com/training/displaying-bitmaps/load-bitmap.html.但这是另一个话题。

这对我运行Kitkat的Nexus 4不起作用,但对运行4.1.2的Galaxy S3起作用。
@Dan2552 哪个部分不工作?你有没有得到任何异常?
结果发现我使用了错误的意图调用到画廊。我使用的是一个用于任何类型的文件,但有一个文件扩展名过滤器。
多么简单的答案啊,谢谢你!"。对于关注这个答案的其他人来说,'cxt'指的是当前的上下文,通常是'this'。
这可能意味着该文件不在那里。URI似乎没有问题。
LEO
LEO
发布于 2014-02-05
0 人赞同

我相信已经发布的回复应该能让人们朝着正确的方向前进。然而,这是我所做的,对我正在更新的传统代码来说是有意义的。传统的代码是使用画廊的URI来改变并保存图片。

在4.4(和google drive)之前,URI看起来是这样的。 content://media/external/images/media/41

正如问题中所述,它们更多时候是这样的。 content://com.android.providers.media.documents/image:3951

由于我需要保存图像的能力,并且不干扰已经存在的代码,我只是从画廊复制了URI到应用程序的数据文件夹中。然后从数据文件夹中保存的图像文件中导出一个新的URI。

这是一个想法。

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");
    //Copy URI contents into temporary file.
    try {
        tempFile.createNewFile();
        copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
    catch (IOException e) {
        //Log Error
    //Now fetch the new URI
    Uri newUri = Uri.fromFile(tempFile);
    /* Use new URI object just like you used to */

注意 - copyAndClose()只是做文件I/O,将InputStream复制到FileOutputStream。这段代码没有公布。

greaterKing
很聪明。我也需要实际的文件尿素。
你是我的英雄,这正是我所需要的!对Google Drive的文件也很有效。
跳出框框思考,对吗? :D 这段代码的效果与我所期望的完全一样。
发布copyAndClose的代码,答案并不完整。
Bringoff
Bringoff
发布于 2014-02-05
0 人赞同

只是想说 这个答案 我使用它很久了,没有任何问题。但是前段时间我发现了一个问题,DownloadsProvider返回的URI格式为 content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf ,因此应用程序在使用 NumberFormatException 时崩溃,因为它不可能解析出长的URI段。但是 raw: 段包含直接的URI,可以用来检索一个被引用的文件。所以我通过替换 isDownloadsDocument(uri) 来修复它。 if 的内容。

final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
    return id.replaceFirst("raw:", "");
try {
    final Uri contentUri = ContentUris.withAppendedId(
            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
    Log.e("FileUtils", "Downloads provider returned unexpected uri " + uri.toString(), e);
    return null;
    
运作完美!谢谢你
Perfecto, Thx @Bringoff
Grzegorz Pawełczuk
Grzegorz Pawełczuk
发布于 2014-02-05
0 人赞同

我将多个答案合并为一个工作方案,其结果是文件路径

Mime类型与例子的目的无关。

            Intent intent;
            if(Build.VERSION.SDK_INT >= 19){
                intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
            }else{
                intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setType("application/octet-stream");
            if(isAdded()){
                startActivityForResult(intent, RESULT_CODE);
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if( requestCode == RESULT_CODE && resultCode == Activity.RESULT_OK) {
        Uri uri = data.getData();
        if (uri != null && !uri.toString().isEmpty()) {
            if(Build.VERSION.SDK_INT >= 19){
                final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
                //noinspection ResourceType
                getActivity().getContentResolver()
                        .takePersistableUriPermission(uri, takeFlags);
            String filePath = FilePickUtils.getSmartFilePath(getActivity(), uri);
            // do what you need with it...

FilePickUtils

import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
public class FilePickUtils {
    private static String getPathDeprecated(Context ctx, Uri uri) {
        if( uri == null ) {
            return null;
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = ctx.getContentResolver().query(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        return uri.getPath();
    public static String getSmartFilePath(Context ctx, Uri uri){
        if (Build.VERSION.SDK_INT < 19) {
            return getPathDeprecated(ctx, uri);
        return  FilePickUtils.getPath(ctx, uri);
    @SuppressLint("NewApi")
    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());
    
我面临的问题是.... uri.getPath()返回的是带有/external的uri,它没有返回路径。我添加了这个else if ("content".equalsIgnoreCase(uri.getScheme()))块,现在效果不错。
filePath is getting null...在uri中:content://com.android.externalstorage.documents/799B-1419%3AScreenshot%2FScreenshot_20181117_162826.png
Vasanth
Vasanth
发布于 2014-02-05
0 人赞同

Question

如何从URI中获取实际的文件路径

据我所知,我们不需要从URI中获取文件路径,因为在大多数情况下,我们可以直接使用URI来完成我们的工作(比如1.获取位图 2.向服务器发送文件,等等)。

1. Sending to the server

我们可以直接使用URI将文件发送至服务器。

使用URI我们可以得到InputStream,我们可以使用MultiPartEntity直接将其发送到服务器。

* Used to form Multi Entity for a URI (URI pointing to some file, which we got from other application). * @param uri URI. * @param context Context. * @return Multi Part Entity. public MultipartEntity formMultiPartEntityForUri(final Uri uri, final Context context) { MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, Charset.forName("UTF-8")); try { InputStream inputStream = mContext.getContentResolver().openInputStream(uri); if (inputStream != null) { ContentBody contentBody = new InputStreamBody(inputStream, getFileNameFromUri(uri, context)); multipartEntity.addPart("[YOUR_KEY]", contentBody); catch (Exception exp) { Log.e("TAG", exp.getMessage()); return multipartEntity; * Used to get a file name from a URI. * @param uri URI. * @param context Context. * @return File name from URI. public String getFileNameFromUri(final Uri uri, final Context context) { String fileName = null; if (uri != null) { // Get file name. // File Scheme. if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { File file = new File(uri.getPath()); fileName = file.getName(); // Content Scheme. else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null); if (returnCursor != null && returnCursor.moveToFirst()) { int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); fileName = returnCursor.getString(nameIndex); returnCursor.close(); return fileName;

2.从URI获取BitMap

如果URI指向图像,那么我们将得到位图,否则为空。

* Used to create bitmap for the given URI. * 1. Convert the given URI to bitmap. * 2. Calculate ratio (depending on bitmap size) on how much we need to subSample the original bitmap. * 3. Create bitmap bitmap depending on the ration from URI. * 4. Reference - http://stackoverflow.com/questions/3879992/how-to-get-bitmap-from-an-uri * @param context Context. * @param uri URI to the file. * @param bitmapSize Bitmap size required in PX. * @return Bitmap bitmap created for the given URI. * @throws IOException public static Bitmap createBitmapFromUri(final Context context, Uri uri, final int bitmapSize) throws IOException { // 1. Convert the given URI to bitmap. InputStream input = context.getContentResolver().openInputStream(uri); BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); onlyBoundsOptions.inJustDecodeBounds = true; onlyBoundsOptions.inDither = true;//optional onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional BitmapFactory.decodeStream(input, null, onlyBoundsOptions); input.close(); if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) { return null; // 2. Calculate ratio. int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth; double ratio = (originalSize > bitmapSize) ? (originalSize / bitmapSize) : 1.0; // 3. Create bitmap. BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio); bitmapOptions.inDither = true;//optional bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional input = context.getContentResolver().openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions); input.close(); return bitmap; * For Bitmap option inSampleSize - We need to give value in power of two. * @param ratio Ratio to be rounded of to power of two. * @return Ratio rounded of to nearest power of two. private static int getPowerOfTwoForSampleRatio(final double ratio) { int k = Integer.highestOneBit((int) Math.floor(ratio)); if (k == 0) return 1; else return k;

Comments

  • Android doesn't provide any methods to get file path from a URI, and in most of the above answers we have hard coded some constants, which may break in feature release (sorry, I may be wrong).
  • Before going directly going to a solution of the getting file path from a URI, try if you can solve your use case with a URI and Android default methods.
  • Reference

  • https://developer.android.com/guide/topics/providers/content-provider-basics.html
  • https://developer.android.com/reference/android/content/ContentResolver.html
  • https://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/content/InputStreamBody.html
  • 谢谢你。 这样使用Uri和ContentResolver大大简化了我处理文件的应用。
    Morten Holmgaard
    Morten Holmgaard
    发布于 2014-02-05
    0 人赞同

    这个Android库可以处理KitKat(包括旧版本--2.1+)中的案例变化。
    https://github.com/iPaulPro/aFileChooser

    使用 String path = FileUtils.getPath(context, uri) 将返回的Uri转换为可在所有操作系统版本上使用的路径字符串。 更多信息请看这里。 https://stackoverflow.com/a/20559175/860488

    Anthonyeef
    Anthonyeef
    发布于 2014-02-05
    0 人赞同

    对于那些仍在使用@Paul Burke的代码的Android SDK 23及以上版本的用户,如果你的项目遇到错误,说你缺少EXTERNAL_PERMISSION,而你非常确定你已经在AndroidManifest.xml文件中添加了用户权限。这是因为你可能在Android API 23或以上版本中,谷歌让你在运行时进行访问文件的操作时,有必要再次保证权限。

    That means: If your SDK version is 23 or above, you are asked for READ & WRITE permission while you are selecting the picture file and want to know the URI of it.

    以下是我的代码,除了Paul Burke的解决方案之外。我加入这些代码后,我的项目开始正常工作了。

    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static final String[] PERMISSINOS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    public static void verifyStoragePermissions(Activity activity) {
        int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSINOS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
    

    And in your activity&fragment where you are asking for the URI:

    private void pickPhotoFromGallery() {
        CompatUtils.verifyStoragePermissions(this);
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        // startActivityForResult(intent, REQUEST_PHOTO_LIBRARY);
        startActivityForResult(Intent.createChooser(intent, "选择照片"),
                REQUEST_PHOTO_LIBRARY);
    

    在我的例子中,CompatUtils.java是我定义verifyStoragePermissions方法的地方(作为静态类型,所以我可以在其他活动中调用它)。

    另外,如果你在调用verifyStoragePermissions方法之前先做一个if状态,看看当前的SDK版本是否在23以上,应该会更有意义。

    0 人赞同

    这就是我的工作。

    Uri selectedImageURI = data.getData();    imageFile = new File(getRealPathFromURI(selectedImageURI)); 
    private String getRealPathFromURI(Uri contentURI) {
      Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
      if (cursor == null) { // Source is Dropbox or other similar local file path
          return contentURI.getPath();
          } else { 
          cursor.moveToFirst(); 
          int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
          return cursor.getString(idx); 
      

    注意:managedQuery()方法已被废弃,所以我不使用它了。

    本回答来自m3n0R的问题android通过Uri.getPath()获得真实路径。而我并不要求任何荣誉。我只是认为还没有解决这个问题的人可以使用这个。

    这不是对KitKat上新的画廊应用(严格来说是 "媒体文件提供者 "应用)的回答。
    提问者所说的 "画廊 "应用可能是kitkat上的新文件采撷器。顺便说一下。 addictivetips.com/android/...
    我做了类似的事情,在Nexus 5X上得到了IndexOutOfBound,Android 6在这一行。替换代码0
    Quentin G.
    Quentin G.
    发布于 2014-02-05
    0 人赞同

    我已经尝试了这里的几个答案,我想我有一个解决方案,每次都能成功,而且也能管理权限。

    它是基于LEO的巧妙解决方案的。这个帖子应该包含了你需要的所有代码,它应该可以在任何手机和安卓版本上运行;)

    为了拥有从SD卡中挑选文件的能力,你需要在清单中加入这个。

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    

    Constants:

    private static final int PICK_IMAGE = 456; // Whatever number you like
    public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL = 28528; // Whatever number you like
    public static final String FILE_TEMP_NAME = "temp_image"; // Whatever file name you like
    

    Check permission and launchImagePick if possible

    if (ContextCompat.checkSelfPermission(getThis(),
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(getThis(),
                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                MY_PERMISSIONS_REQUEST_READ_EXTERNAL);
    else {
        launchImagePick();
    

    Permission response

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull
                                             String permissions[],
                                           @NonNull
                                             int[] grantResults) {
        if (manageReadExternalPermissionResponse(this, requestCode, grantResults)) {
            launchImagePick();
    

    Manage permission response

    public static boolean manageReadExternalPermissionResponse(final Activity activity, int requestCode, int[] grantResults) {
        if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL) {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission was granted, yay! Do the
                // contacts-related task you need to do.
                return true;
            } else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
                boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity,
                        Manifest.permission.READ_EXTERNAL_STORAGE);
                if (!showRationale) {
                    // The user also CHECKED "never ask again".
                    // You can either enable some fall back,
                    // disable features of your app
                    // or open another dialog explaining
                    // again the permission and directing to
                    // the app setting.
                } else {
                    // The user did NOT check "never ask again".
                    // This is a good place to explain the user
                    // why you need the permission and ask if he/she wants
                    // to accept it (the rationale).
            } else {
                // Permission denied, boo! Disable the
                // functionality that depends on this permission.
        return false;
    

    启动图像选择

    private void launchImagePick() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        startActivityForResult(intent, PICK_IMAGE);
        // see onActivityResult
    

    管理图像提取响应

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_IMAGE) {
            if (resultCode == Activity.RESULT_OK) {
                if (data != null && data.getData() != null) {
                    try {
                         InputStream inputStream = getContentResolver().openInputStream(data.getData())
                         if (inputStream != null) {
                            // No special persmission needed to store the file like that
                            FileOutputStream fos = openFileOutput(FILE_TEMP_NAME, Context.MODE_PRIVATE);
                            final int BUFFER_SIZE = 1 << 10 << 3; // 8 KiB buffer
                            byte[] buffer = new byte[BUFFER_SIZE];
                            int bytesRead = -1;
                            while ((bytesRead = inputStream.read(buffer)) > -1) {
                                fos.write(buffer, 0, bytesRead);
                            inputStream.close();
                            fos.close();
                            File tempImageFile = new File(getFilesDir()+"/"+FILE_TEMP_NAME);
                            // Do whatever you want with the File
                            // Delete when not needed anymore
                            deleteFile(FILE_TEMP_NAME);
                    catch (Exception e) {
                        e.printStackTrace();
                } else {
                    // Error display
            } else {
                // The user did not select any image
    

    这就是所有的人;这对我的所有电话都有效。

    0101100101
    0101100101
    发布于 2014-02-05
    0 人赞同

    如果有人感兴趣,我为 ACTION_GET_CONTENT 做了一个工作的Kotlin版本。

    var path: String = uri.path // uri = any content Uri
    val databaseUri: Uri
    val selection: String?
    val selectionArgs: Array<String>?
    if ("/document/image:" in path || "/document/image%3A" in path) {
        // files selected from "Documents"
        databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        selection = "_id=?"
        selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
    } else { // files selected from all other sources, especially on Samsung devices
        databaseUri = uri
        selection = null
        selectionArgs = null
    try {
        val projection = arrayOf(MediaStore.Images.Media.DATA,
            MediaStore.Images.Media._ID,
            MediaStore.Images.Media.ORIENTATION,
            MediaStore.Images.Media.DATE_TAKEN) // some example data you can query
        val cursor = context.contentResolver.query(databaseUri,
            projection, selection, selectionArgs, null)
        if (cursor.moveToFirst()) {
            // do whatever you like with the data
        cursor.close()
    } catch (e: Exception) {
        Log.e(TAG, e.message, e)
        
    我只想要一个kotlin的工作代码。这对我来说是有效的。
    saranya
    saranya
    发布于 2014-02-05
    0 人赞同

    请尽量避免使用takePersistableUriPermission方法,因为它给我带来了运行时异常。 *从画廊中选择。

    public void selectFromGallery() {
        if (Build.VERSION.SDK_INT < AppConstants.KITKAT_API_VERSION) {
            Intent intent = new Intent(); 
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            ((Activity)mCalledContext).startActivityForResult(intent,AppConstants.GALLERY_INTENT_CALLED);
        } else {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("image/*");
            ((Activity)mCalledContext).startActivityForResult(intent, AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED);
    

    OnActivity用于处理图像数据的结果。

    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        //gallery intent result handling before kit-kat version
        if(requestCode==AppConstants.GALLERY_INTENT_CALLED 
                && resultCode == RESULT_OK) {
            Uri selectedImage = data.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String filePath = cursor.getString(columnIndex);
            cursor.close();
            photoFile = new File(filePath);
            mImgCropping.startCropImage(photoFile,AppConstants.REQUEST_IMAGE_CROP);
        //gallery intent result handling after kit-kat version
        else if (requestCode == AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED 
                && resultCode == RESULT_OK) {
            Uri selectedImage = data.getData();
            InputStream input = null;
            OutputStream output = null;
            try {
                //converting the input stream into file to crop the 
                //selected image from sd-card.
                input = getApplicationContext().getContentResolver().openInputStream(selectedImage);
                try {
                    photoFile = mImgCropping.createImageFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }catch(Exception e) {
                    e.printStackTrace();
                output = new FileOutputStream(photoFile);
                int read = 0;
                byte[] bytes = new byte[1024];
                while ((read = input.read(bytes)) != -1) {
                    try {
                        output.write(bytes, 0, read);
                    } catch (IOException e) {
                        e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
        
    在第二种情况下,你在哪里显示图像?
    对不起,我没有在else中加入这行代码,如果mImgCropping.startCropImage(photoFile,AppConstants.REQUEST_IMAGE_CROP); 再次需要根据我的项目需要调用imagecropping函数。
    photoFile和mImgCropping是什么文件类型?
    fattire
    fattire
    发布于 2014-02-05
    0 人赞同

    这完全是一个黑客,但我是这样做的...

    因此,在玩设置一个 DocumentsProvider ,我注意到, 示例代码 (在 getDocIdForFile 中,大约第450行)根据文件相对于你给它的指定根(也就是你在第96行设置的 mBaseDir )的(唯一)路径,为选定的文件生成一个唯一的ID。

    So the URI ends up looking something like:

    content://com.example.provider/document/root:path/to/the/file

    正如文档所说,它假设只有一个根(在我的例子中是 Environment.getExternalStorageDirectory() ,但你可能在其他地方使用......然后它从根开始获取文件路径,并使其成为唯一的ID,前面加上" root: "。 所以我可以通过消除uri.getPath()中的 "/document/root: 部分来确定路径,通过这样的方式创建一个实际的文件路径。

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // check resultcodes and such, then...
    uri = data.getData();
    if (uri.getAuthority().equals("com.example.provider"))  {
        String path = Environment.getExternalStorageDirectory(0.toString()
                     .concat("/")
                     .concat(uri.getPath().substring("/document/root:".length())));
        doSomethingWithThePath(path); }
    else {
        // another provider (maybe a cloud-based service such as GDrive)
        // created this uri.  So handle it, or don't.  You can allow specific
        // local filesystem providers, filter non-filesystem path results, etc.
    

    我知道。 这很可耻,但它很有效。 再说一遍,这有赖于你用你的own你的应用程序中的文档提供者,以生成文档ID。

    (另外,还有一种更好的方法来建立路径,即不认为"/"是路径分隔符,等等。 但你会明白这个意思的)。

    用一个更疯狂的想法来回答我自己--如果你的应用程序已经在处理来自外部文件选取器的 file:// 意图,你也可以检查权限。如果是这样的话,你也可以使用路径来 "伪造 "一个新的 file:// 意图,使用你提取的路径,然后 StartActivity() ,让你的应用程序接收它。 我知道,很糟糕。
    Rafa
    Rafa
    发布于 2014-02-05
    0 人赞同

    This worked fine for me:

    else if(requestCode == GALLERY_ACTIVITY_NEW && resultCode == Activity.RESULT_OK)
        Uri uri = data.getData();
        Log.i(TAG, "old uri =  " + uri);
        dumpImageMetaData(uri);
        try {
            ParcelFileDescriptor parcelFileDescriptor =
                    getContentResolver().openFileDescriptor(uri, "r");
            FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
            Log.i(TAG, "File descriptor " + fileDescriptor.toString());
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
            options.inSampleSize =
               BitmapHelper.calculateInSampleSize(options,
                                                  User.PICTURE_MAX_WIDTH_IN_PIXELS,
                                                  User.PICTURE_MAX_HEIGHT_IN_PIXELS);
            options.inJustDecodeBounds = false;
            Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
            imageViewPic.setImageBitmap(bitmap);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            // get byte array here
            byte[] picData = stream.toByteArray();
            ParseFile picFile = new ParseFile(picData);
            user.setProfilePicture(picFile);
        catch(FileNotFoundException exc)
            Log.i(TAG, "File not found: " + exc.toString());
        
    Rafa
    忘记dumpImageMetaData(uri);它是不必要的。
    Morphing Coffee
    Morphing Coffee
    发布于 2014-02-05
    0 人赞同

    Building up on 保罗-伯克的回答 我在解决外部SD卡的URI路径方面遇到了很多问题,因为大多数建议的 "内置 "函数返回的路径都不能被解析为文件。

    However, this is my 他的方法 // TODO处理非主卷 .

    String resolvedPath = "";
    File[] possibleExtSdComposites = context.getExternalFilesDirs(null);
    for (File f : possibleExtSdComposites) {
        // Reset final path
        resolvedPath = "";
        // Construct list of folders
        ArrayList<String> extSdSplit = new ArrayList<>(Arrays.asList(f.getPath().split("/")));
        // Look for folder "<your_application_id>"
        int idx = extSdSplit.indexOf(BuildConfig.APPLICATION_ID);
        // ASSUMPTION: Expected to be found at depth 2 (in this case ExtSdCard's root is /storage/0000-0000/) - e.g. /storage/0000-0000/Android/data/<your_application_id>/files
        ArrayList<String> hierarchyList = new ArrayList<>(extSdSplit.subList(0, idx - 2));
        // Construct list containing full possible path to the file
        hierarchyList.add(tail);
        String possibleFilePath = TextUtils.join("/", hierarchyList);
        // If file is found --> success
        if (idx != -1 && new File(possibleFilePath).exists()) {
            resolvedPath = possibleFilePath;
            break;
    if (!resolvedPath.equals("")) {
        return resolvedPath;
    } else {
        return null;
    

    请注意,这取决于层次结构,每个手机制造商可能都不一样--我没有对它们进行测试(到目前为止,它在Xperia Z3 API 23和三星Galaxy A3 API 23上运行良好)。

    如果它在其他地方表现不佳,请确认。

    Ilyas Arafath
    Ilyas Arafath
    发布于 2014-02-05
    0 人赞同

    for this type of uri content://com.android.providers.media.documents/document/document%3A19298 uri.getAuthority() 是这些中的任何一个

    "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
    

    use this function

    private static String getDriveFilePath(Uri uri, Context context) {
            Uri returnUri = uri;
            Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            String size = (Long.toString(returnCursor.getLong(sizeIndex)));
            File file = new File(context.getCacheDir(), name);
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                FileOutputStream outputStream = new FileOutputStream(file);
                int read = 0;
                int maxBufferSize = 1 * 1024 * 1024;
                int bytesAvailable = inputStream.available();
                //int bufferSize = 1024;
                int bufferSize = Math.min(bytesAvailable, maxBufferSize);
                final byte[] buffers = new byte[bufferSize];
                while ((read = inputStream.read(buffers)) != -1) {
                    outputStream.write(buffers, 0, read);
                Log.e("File Size", "Size " + file.length());
                inputStream.close();
                outputStream.close();
                Log.e("File Path", "Path " + file.getPath());
                Log.e("File Size", "Size " + file.length());
            } catch (Exception e) {
                Log.e("Exception", e.getMessage());
            return file.getPath();
        
    parvez rafi
    parvez rafi
    发布于 2014-02-05
    0 人赞同

    @paul burke的答案对于API级别19及以上的相机和图库图片都能正常工作,但如果你的安卓项目的最低SDK设置为19以下,它就不能工作,而且上面提到的一些答案对于图库和相机都不能工作。好吧,我修改了@paul burke的代码,它在API级别低于19的情况下可以工作。以下是该代码。

    public static String getPath(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >=
                                 Build.VERSION_CODES.KITKAT;
        Log.i("URI",uri+"");
        String result = uri+"";
        // DocumentProvider
        // if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        if (isKitKat && (result.contains("media.documents"))) {
            String[] ary = result.split("/");
            int length = ary.length;
            String imgary = ary[length-1];
            final String[] dat = imgary.split("%3A");
            final String docId = dat[1];
            final String type = dat[0];
            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            else if ("video".equals(type)) {
            else if ("audio".equals(type)) {
            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                dat[1]
            return getDataColumn(context, contentUri, selection, selectionArgs);
        if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        return null;
    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;
        
    我收到java.lang.IllegalArgumentException。在选择Google Doc图片时,无法提供所要求的任何列
    @dirkoneill 我得到了同样的Exception。你找到修复方法了吗?
    ashwin
    ashwin
    发布于 2014-02-05
    0 人赞同

    你的问题的答案是,你需要有权限。在你的manifest.xml文件中输入以下代码。

    <uses-sdk  android:minSdkVersion="8"   android:targetSdkVersion="18" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>