【我的Android进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;

简介: 之前开发的一个和第三方合作的apk,在之前公司的 Android 5.1 系统的手表上运行正常,今天在公司新开发的 Android 7.1系统的手表上运行的时候,使用 DownloadManager 下载之后,查询下载状态的时候,报了异常java.

之前开发的一个和第三方合作的apk,在之前公司的 Android 5.1 系统的手表上运行正常,今天在公司新开发的 Android 7.1系统的手表上运行的时候,使用 DownloadManager 下载之后,查询下载状态的时候,报了异常

java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated; use ContentResolver.openFileDescriptor() instead
AI 代码解读

异常详细信息如下:

03-17 15:59:43.288 31487-31487/com.netease.xtc.cloudmusic E/CloudMusicDownloadService: DownloadChangeObserver.onChange() throwable = java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated; use ContentResolver.openFileDescriptor() instead
                                                                                           at android.app.DownloadManager$CursorTranslator.getString(DownloadManager.java:1545)
                                                                                           at com.netease.xtc.cloudmusic.services.download.CloudMusicDownloadService.queryDownloadStatus(CloudMusicDownloadService.java:634)
                                                                                           at com.netease.xtc.cloudmusic.services.download.CloudMusicDownloadService.access$900(CloudMusicDownloadService.java:55)
                                                                                           at com.netease.xtc.cloudmusic.services.download.CloudMusicDownloadService$DownloadChangeObserver$3.call(CloudMusicDownloadService.java:590)
                                                                                           at com.netease.xtc.cloudmusic.services.download.CloudMusicDownloadService$DownloadChangeObserver$3.call(CloudMusicDownloadService.java:587)
                                                                                           at rx.Observable.unsafeSubscribe(Observable.java:8666)
                                                                                           at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
                                                                                           at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:220)
                                                                                           at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
                                                                                           at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
                                                                                           at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                                                           at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
                                                                                           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                                                                                           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                                                                                           at java.lang.Thread.run(Thread.java:761)
AI 代码解读

跳转到报错的地方,如下图所示:
这里写图片描述

在运行下面两行代码的时候报错了。

  int fileNameIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
  String fileName = c.getString(fileNameIdx);
AI 代码解读

而且 DownloadManager.COLUMN_LOCAL_FILENAME 已经是被废弃的常量了,点击查看源代码如下所示:

 /**
     * Path to the downloaded file on disk.
     * <p>
     * Note that apps may not have filesystem permissions to directly access
     * this path. Instead of trying to open this path directly, apps should use
     * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access.
     *
     * @deprecated apps should transition to using
     *             {@link ContentResolver#openFileDescriptor(Uri, String)}
     *             instead.
     */
    @Deprecated
    public final static String COLUMN_LOCAL_FILENAME = "local_filename";
AI 代码解读

Android 在 Android 7.0 或更高版本开发的应用在尝试访问DownloadManager.COLUMN_LOCAL_FILENAME 时会触发java.lang.SecurityException。

Android官方建议我们使用 ContentResolver#openFileDescriptor(Uri, String)来获取文件相关信息。源代码如下所示:

 /**
     * Open a raw file descriptor to access data under a URI.  This
     * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
     * underlying {@link ContentProvider#openFile}
     * ContentProvider.openFile()} method, so will <em>not</em> work with
     * providers that return sub-sections of files.  If at all possible,
     * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
     * will receive a FileNotFoundException exception if the provider returns a
     * sub-section of a file.
     *
     * <h5>Accepts the following URI schemes:</h5>
     * <ul>
     * <li>content ({@link #SCHEME_CONTENT})</li>
     * <li>file ({@link #SCHEME_FILE})</li>
     * </ul>
     *
     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
     * on these schemes.
     * <p>
     * If opening with the exclusive "r" or "w" modes, the returned
     * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
     * of data. Opening with the "rw" mode implies a file on disk that supports
     * seeking. If possible, always use an exclusive mode to give the underlying
     * {@link ContentProvider} the most flexibility.
     * <p>
     * If you are writing a file, and need to communicate an error to the
     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
     *
     * @param uri The desired URI to open.
     * @param mode The file mode to use, as per {@link ContentProvider#openFile
     * ContentProvider.openFile}.
     * @return Returns a new ParcelFileDescriptor pointing to the file.  You
     * own this descriptor and are responsible for closing it when done.
     * @throws FileNotFoundException Throws FileNotFoundException if no
     * file exists under the URI or the mode is invalid.
     * @see #openAssetFileDescriptor(Uri, String)
     */
    public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
            @NonNull String mode) throws FileNotFoundException {
        return openFileDescriptor(uri, mode, null);
    }
AI 代码解读

这里写图片描述

查看Android 官方文档,关于Android 7.0 的权限管理更改,如下图所示:

参考链接为:
https://developer.android.google.cn/about/versions/nougat/android-7.0-changes.html#sharing-files

这里写图片描述

因此为了解决这个异常,我们有以下两个方法解决。

方法一、使用 ContentResolver#openFileDescriptor(Uri, String)来替代访问由 DownloadManager 公开的文件。

方法二、使用DownloadManager.COLUMN_LOCAL_URI查出文件Uri,然后使用Uri new一个File,再获取File的相关信息,如下所示:

int fileUriIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
String fileUri = c.getString(fileUriIdx);
String fileName = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
    if (fileUri != null) {
        fileName = Uri.parse(fileUri).getPath();
    }
} else {
    //Android 7.0以上的方式:请求获取写入权限,这一步报错
    //过时的方式:DownloadManager.COLUMN_LOCAL_FILENAME
    int fileNameIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
    fileName = c.getString(fileNameIdx);
}
AI 代码解读

运行之后,不会报错,并且能够获取到正常的文件名。

参考链接
1. https://developer.android.google.cn/about/versions/nougat/android-7.0-changes.html#sharing-files
2. http://www.cnblogs.com/dazhao/p/6547811.html
3. http://www.jianshu.com/p/56b9fb319310


作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址: http://blog.csdn.net/ouyang_peng/article/details/62891782

这里写图片描述

目录
打赏
0
0
0
0
38
分享
相关文章
|
4月前
|
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
133 1
如何避免 Java 中的 TimeoutException 异常
在Java中,`TimeoutException`通常发生在执行操作超过预设时间时。要避免此异常,可以优化代码逻辑,减少不必要的等待;合理设置超时时间,确保其足够完成正常操作;使用异步处理或线程池管理任务,提高程序响应性。
255 13
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
在BeetISQL 2.13.8版本中,客户使用batch insert向yashandb表插入数据并尝试获取自动生成的sequence id时,出现类型转换异常。原因是beetlsql在prepareStatement时未指定返回列,导致yashan JDBC驱动返回rowid(字符串),与Java Bean中的数字类型tid不匹配。此问题影响业务流程,使无法正确获取sequence id。解决方法包括:1) 在batchInsert时不返回自动生成的sequence id;2) 升级至BeetISQL 3,其已修正该问题。
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
|
4月前
|
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
71 1
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
136 14
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
224 5
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
161 8
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
154 6
|
4月前
|
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
103 1

热门文章

最新文章