最近实现了的一个文件选择功能,选择文件后闪退或者无法选择文件,楼主看了一下,是使用了模块库里面的(selectFile)模块.
===================================================================
根据这个模块的功能,应该是调用了安装自带的文件管理器
- Intent intent = new Intent("android.intent.action.GET_CONTENT");
- intent.setType("*/*");
- intent.addCategory("android.intent.category.OPENABLE");
经过对比:
发现华为手机返回的路径格式如下 : content://com.android.providers.downloads.documents/document/raw:/storage/emulated/0/Download/xxx
其它手机的返回格式下:
content://com.android.providers.downloads.documents/document/img:/3
报错日志一般都是无法将String转换为Double
java.lang.NumberFormatException: For input string:"raw:/storage/emulated/0/Download/WeiXin/测试.pdf"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at com.sz.mpvmaster.utils.FileUtil.getFilePathFromUri(FileUtil.java:45)
at com.sz.mpvmaster.next.FileActivity.lambda$initView$0$com-sz-mpvmaster-next-FileActivity(FileActivity.java:73)
at com.sz.mpvmaster.next.FileActivity$$ExternalSyntheticLambda0.onActivityResult(Unknown Source:4)
at androidx.activity.result.ActivityResultRegistry$1.onStateChanged(ActivityResultRegistry.java:148)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
at androidx.lifecycle.ReportFragment$LifecycleCallbacks.onActivityPostStarted(ReportFragment.java:187)
at android.app.Activity.dispatchActivityPostStarted(Activity.java:1307)
at android.app.Activity.performStart(Activity.java:8277)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4089)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:235)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:215)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:187)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2618)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8673)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
针对下载目录文件里面 , 获取真实路径的方式 , 一般是通过文件ID去文件数据库里查询文件真实路径,华为的手机,可以直接截取 raw://的路径返回,
因国内手机厂商基本上都对android做过改动,无法像之前一样根据Id通过查询 content://downloads/public_downloads
目录获取到文件的真实路径,有的手机的路径是 content://downloads/public_downloads ,
而有的手机是 content://downloads/my_downloads , 有的则是
content://downloads/all_downloads, 因此需要每一种路径下都查询是否能根据文件ID获取到文件才可
最为简单的一种方式就是下面这种,直接x掉raw.
String id = DocumentsContract.getDocumentId(imageUri);
filePath = id.substring(4);
但是查阅了很多相关资料好像并非这么简单,为了保险起见,可参考下列代码进行处理。
具体判断代码如下:
final String id = DocumentsContract.getDocumentId(uri);
if (id != null && id.startsWith("raw:")) {
return id.substring(4);
}
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) {}
}
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
String fileName = getFileName(context, uri);
File cacheDir = getDocumentCacheDir(context);
File file = generateFileName(fileName, cacheDir);
String destinationPath = null;
if (file != null) {
destinationPath = file.getAbsolutePath();
saveFileFromUri(context, uri, destinationPath);
}
return destinationPath;
大家可以自己动手去实现(getFileName,getDocumentCacheDir,generateFileName等模块) , 也可以等待我上传相应的模块来解决这个问题。
getFileName():
public static String getFileName(@NonNull Context context, Uri uri) {
String mimeType = context.getContentResolver().getType(uri);
String filename = null;
if (mimeType == null && context != null) {
String path = getPath(context, uri);
if (path == null) {
filename = getName(uri.toString());
} else {
File file = new File(path);
filename = file.getName();
}
} else {
Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null);
if (returnCursor != null) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
returnCursor.close();
}
}
return filename;
}
getDocumentCacheDir():
public static File getDocumentCacheDir(@NonNull Context context) {
File dir = new File(context.getCacheDir(), DOCUMENTS_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
generateFileName():
@Nullable
public static File generateFileName(@Nullable String name, File directory) {
if (name == null) {
return null;
}
File file = new File(directory, name);
if (file.exists()) {
String fileName = name;
String extension = "";
int dotIndex = name.lastIndexOf('.');
if (dotIndex > 0) {
fileName = name.substring(0, dotIndex);
extension = name.substring(dotIndex);
}
int index = 0;
while (file.exists()) {
index++;
name = fileName + '(' + index + ')' + extension;
file = new File(directory, name);
}
}
try {
if (!file.createNewFile()) {
return null;
}
} catch (IOException e) {
//Log.w(TAG, e);
return null;
}
//logDir(directory);
return file;
}