Androidd打开文件选择器并返回文件的真实路径——听风便是雨,倚栏卧人间

        最近老板喊话做一个涉及到文件上传的项目,文件上传嘛,那肯定就需要选择文件了。选择文件想必大家都不陌生,手机端,电脑端都经常用到——点击一个打开文件选择器的小图标,进入文件选择器,选择好文件之后,啪,返回一个文件所在的真实路径。。。当时想了想貌似也挺简单的,就网上查了点资料然后开始自己码代码,码完之后各种修改(主要是各种权限,所以亲们记得加上)然后欢天喜地的开始真机测试,哟!成功了哎!满心欢喜的来来回回拨弄了好几次,好吧。。。让你浪,出问题了吧...=.=...

        在经过我来来回回的测试之后发现,参照网上的方法,一个“file”类型的在回调里面直接调用

uri.getPath();
返回的就是文件的真实路径,然后一个是“content”类型的,参照了一些网上的方法:
        Uri uri = data.getData();//得到uri,后面就是将uri转化成file的过程。
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor actualimagecursor = managedQuery(uri, proj, null, null, null);
        int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        actualimagecursor.moveToFirst();
        String img_path = actualimagecursor.getString(actual_image_column_index);
        File file = new File(img_path);
        Toast.makeText(MainActivity.this, file.toString(), Toast.LENGTH_SHORT).show();

        然后发现有些能正常返回文件的真实路径,有些则不能,着实让我郁闷了好久...郁闷之余,有问题咱也得解决不是,干瞪眼也于事无补;为了找出是什么问题,我决定将每一个测试的URI打印出来看看是怎么回事,以下是我的真机honor7打开文件选择器的界面:

      Androidd打开文件选择器并返回文件的真实路径——听风便是雨,倚栏卧人间_第1张图片

        我分别对图片、视频、音频、内部存储空间、浏览器-文件管理以及文件管理选择文件所返回的URI进行了测试,测试结果如下:

1、文件选择器——图片
isMediaDocument***content://com.android.providers.media.documents/document/image%3A23
2、文件选择器——视频
isMediaDocument***content://com.android.providers.media.documents/document/video%3A54934
3、文件选择器——音频
isMediaDocument***content://com.android.providers.media.documents/document/audio%3A35883
4、文件选择器——内部存储空间
isExternalStorageDocument***content://com.android.externalstorage.documents/document/primary%3ATest%2FROC2018421103253.wav
5、文件选择器——浏览器-文件管理
file***file:///storage/emulated/0/kiwi/gamecenter/gameCenter_hy3.apk
6、文件选择器——文件管理(也就是我们平常时查找文件用的手机自带文件管理器)
content***content://media/external/audio/media/72232

        然后我发现了,对于“content”类型,能用上面提到的方法转换成功的,就只有第6点的文件管理所返回的URI能得到正确的文件真实路径,而对1、2、3、4点的URI进行转换时则出现了问题,这到底是为什么呢?经过仔细比对,发现1、2、3、4所对应的URI虽然也都是“content”类型,但是跟第6点所对应的URI来对比,明显发现前者的格式是不一样的,带着疑惑的我上了度娘(想什么呢你们。。),终于发现Android从4.4版本(API_19)开始多了个DocumentsProvider(观察仔细的你们一定也发现了1、2、3、4点里面所返回的URI都包含有“documents”字样对不对),所以上述的方法只适合4.4(不包含)以下版本使用,如果是4.4及以上版本则不好用了,所以,该怎么办呢?答案当然是——贴上代码了!亲们你们说对不对?

        首先,是打开文件选择器的代码:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");//设置类型,我这里是任意类型,任意后缀的可以这样写。
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent,1);

        其次,是回调的代码:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1) {
        if (resultCode == RESULT_OK) {
            Uri uri = data.getData();
            if (uri != null) {
                String path = getPath(this, uri);
                if (path != null) {
                    File file = new File(path);
                    if (file.exists()) {
                        String upLoadFilePath = file.toString();
                        String upLoadFileName = file.getName();
                    }
                }
            }
        }
    }
}

        很多人就问了,getPath(this,uri)方法呢。。。别急,这是在这呢嘛

public 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);
//                Log.i(TAG,"isExternalStorageDocument***"+uri.toString());
//                Log.i(TAG,"docId***"+docId);
//                以下是打印示例:
//                isExternalStorageDocument***content://com.android.externalstorage.documents/document/primary%3ATset%2FROC2018421103253.wav
//                docId***primary:Test/ROC2018421103253.wav
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
//                Log.i(TAG,"isDownloadsDocument***"+uri.toString());
                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)) {
//                Log.i(TAG,"isMediaDocument***"+uri.toString());
                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())) {
//            Log.i(TAG,"content***"+uri.toString());
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
//            Log.i(TAG,"file***"+uri.toString());
            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 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;
    }

    
    public boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }
    
    public boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    public boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

        也许很多人会问,怎么不写个Demo?其实是因为我相信你们啊!核心代码都给出来了难道区区一个布局文件还会写不出?不可能的,这辈子都不可能的。。

        最近在搞Android端发送文件,PC端接收文件这些东东(多大用不知道就是觉得挺好玩的),看看到时候小伙伴如果需求量大的话会在接下来的博客里面写写,讲解一下,到时候会有相应的Demo。

        最后面贴上前面获取的URI经过代码所转换成的文件真实路径供各位小伙伴进行参考:

/storage/emulated/0/Pictures/JPEG_20170427_084319-1775672039.jpg
/storage/emulated/0/BaiduNetdisk/我的资源/Python/02-数学课程/ML_机器学习中的数学班/第10讲 极大似然估计.mp4
/storage/emulated/0/qqmusic/song/薛之谦 - 深深爱过你(前世) [mqms2].flac
/storage/emulated/0/Test/ROC2018421103253.wav
/storage/emulated/0/kiwi/gamecenter/gameCenter_hy3.apk
/storage/emulated/0/Test/ROC2018421111222.wav
        祝大家生活愉快哟~~~~


你可能感兴趣的:(Androidd打开文件选择器并返回文件的真实路径——听风便是雨,倚栏卧人间)