Android文件选择Download目录闪退解决思路及方案(在选择文件时跳到下载内容模块选择里面的文件报错)

文章描述了一个在Android应用中实现文件选择功能时遇到的问题,特别是在华为手机上,由于返回的文件路径格式不同导致NumberFormatException。作者分析了问题的原因,并提供了处理不同手机厂商定制化路径的代码示例,包括尝试不同的contentUriPrefixes和文件复制方法来获取真实路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近实现了的一个文件选择功能,选择文件后闪退或者无法选择文件,楼主看了一下,是使用了模块库里面的(selectFile)模块.

===================================================================
根据这个模块的功能,应该是调用了安装自带的文件管理器

  1. Intent intent = new Intent("android.intent.action.GET_CONTENT");
  2. intent.setType("*/*");
  3. 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;
    }

                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值