开发者社区> 欧阳鹏> 正文

【我的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

异常详细信息如下:

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)

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

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

  int fileNameIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
  String fileName = c.getString(fileNameIdx);

而且 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";

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

这里写图片描述

查看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);
}

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

参考链接
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

这里写图片描述

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【我的Android进阶之旅】解决Center OS 64位系统编译Android APP报错error=2和finished with non-zero exit value 127
一、错误描述 1、问题 java.io.IOException: error=2, 没有那个文件或目录 今天在刚重新搭建好的64位的Center OS上安装好了Android SDK,Jenkins,Git等一系列用于持续集成的环境之后,准备编译下项目试一试,然后Jenkins编译失败,错误如下所示: Caused by: java.
1703 0
【我的Android进阶之旅】 RxJava 理解Backpressure并解决异常 rx.exceptions.MissingBackpressureException
今天测试人员在测试应用APP的时候应用crash了,查看了下crash log如下所示: java.lang.IllegalStateException: Exception thrown on Scheduler.
1358 0
【我的Android进阶之旅】Android目录过长造成错误:Failed to crunch file abc_textfield_search_activated_mtrl_alpha.9.png
一、编译异常描述 一大早来开发一个新的需求,拉取了一个新的分支,然后导入Android Studio之后,编译就报错了,报错如下所示: 错误具体日志如下所示: Information:Gradle tasks [:app:assembleDebug]...
1470 0
java.lang.StackOverflowError异常解决
在hibernate一对多映射中,两个实体都重写了toString()方法,,应用程序递归太深了,所以发生了堆栈溢出。
1325 0
关于异常Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
原文:关于异常Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 关于Microsoft.CSharp.RuntimeBinder.RuntimeBinderException的异常一般来自于两种, 第一种: Predefined type 'Microsoft.CSharp.RuntimeBinder.Binder' is not defined or imported 解决它的办法是,直接在项目引用中添加 Micorsoft.Csharp 就可以了。
1556 0
【我的Android进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;
之前开发的一个和第三方合作的apk,在之前公司的 Android 5.1 系统的手表上运行正常,今天在公司新开发的 Android 7.1系统的手表上运行的时候,使用 DownloadManager 下载之后,查询下载状态的时候,报了异常 java.
1942 0
Redis + Jedis + Spring整合遇到的异常(转)
项目中需要用到缓存,经过比较后,选择了redis,客户端使用jedis连接,也使用到了spring提供的spring-data-redis。配置正确后启动tomcat,发现如下异常: Caused by: org.
1561 0
Java异常--基本概念try...catch...finally
<h1><strong>1、异常:</strong></h1> <p><img src="http://img.blog.csdn.net/20131009101613156" alt=""><br></p> <h1>2、异常处理格式:</h1> <div> <img src="http://img.blog.csdn.net/20131009101751953" alt=""><b
1023 0
+关注
欧阳鹏
一个人,如果你不逼自己一把,你根本不知道自己有多优秀! Talk is cheap, show me the code.
473
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载