URi 查询 Android,Android 版本兼容 — Android 4.4 后根据系统 Uri 查询 AbsoultePath

Android 4.4 后根据系统 Uri 查询 AbsoultePath

b3d2acad941f

这里主要记录一次踩坑的经历。

大家都知道Android 4.4 前后根据Uri查询路径path,方式发生了变化,网上也是各种资料,方案可以说也很成熟。下面是在原有方案的基础上完善的。

import android.content.ContentResolver;

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 FileUtilCompat {

@SuppressLint("NewApi")

public static String getFilePathByUri(Context context, Uri uri) {

// 4.4及之后的 是 DocumentProvider。

// 比如 content://com.android.providers.media.documents/document/image%3A235700

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && 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];

}

}

// DownloadsProvider

else if (isDownloadsDocument(uri)) {

final String id = DocumentsContract.getDocumentId(uri);

//处理某些机型(比如Goole Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4

final String[] split = id.split(":");

final String type = split[0];

if ("raw".equalsIgnoreCase(type)) {

return split[1];

}

String[] contentUriPrefixesToTry = new String[]{

"content://downloads/public_downloads",

"content://downloads/my_downloads",

"content://downloads/all_downloads"

};

for (String contentUriPrefix : contentUriPrefixesToTry) {

Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));

try {

String path = getDataColumn(context, contentUri, null, null);

if (path != null) {

return path;

}

} catch (Exception e) {

}

}

}

// 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);

}

}

// 以 file:// 开头的

else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {

return uri.getPath();

}

// 以 content:// 开头的,比如 content://media/extenral/images/media/17766

// 注意这种情况是一般情况,4.4前后都有

else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {

return getDataColumn(context, uri, null, null);

}

return null;

}

private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

Cursor cursor = null;

final String column = MediaStore.Images.Media.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;

}

private static boolean isExternalStorageDocument(Uri uri) {

return "com.android.externalstorage.documents".equals(uri.getAuthority());

}

private static boolean isDownloadsDocument(Uri uri) {

return "com.android.providers.downloads.documents".equals(uri.getAuthority());

}

private static boolean isMediaDocument(Uri uri) {

return "com.android.providers.media.documents".equals(uri.getAuthority());

}

}

今天偶然遇到一个很奇怪的事情,一个Android 9.0 手机,一个文件夹下的视频文件用我们的应用打不开了。这个文件位于download文件夹下。

经过调试发现,问题出在了 第42行,查询的I这个文件的ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4

很显然这个就是绝对路径并且多了个 raw: ,额 那个成熟的方案并没有处理DownloadsDocumen这种情况。

// DownloadsProvider

final String id = DocumentsContract.getDocumentId(uri);

final String[] split = id.split(":");

final String type = split[0];

if ("raw".equalsIgnoreCase(type)) { //处理某些机型(比如Goole Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4

return split[1];

}

也就是完善后的方案中第 44行 — 第49行

========= 更新日志 ==========

最上面给出的是最后更新的方案 ,更新于2018.11.20

独有的4.4以上处理的只是DocumentProvider,所以普通的处理情况也需要有,我原来的方式过滤掉了最普通的方式。

String[] contentUriPrefixesToTry = new String[]{

"content://downloads/public_downloads",

"content://downloads/my_downloads",

"content://downloads/all_downloads"

};

for (String contentUriPrefix : contentUriPrefixesToTry) {

Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));

try {

String path = getDataColumn(context, contentUri, null, null);

if (path != null) {

return path;

}

} catch (Exception e) {

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值