【我的Android进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;
之前开发的一个和第三方合作的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进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;的更多相关文章
- 【我的Android进阶之旅】解决sqlcipher库:java.lang.IllegalStateException: get field slot from row 0 col 0 failed.
一.背景 最近维护公司的大数据SDK,在大数据SDK里面加入了ANR的监控功能,并将ANR的相关信息通过大数据埋点的方式记录到了数据库中,然后大数据上报的时候上报到大数据平台,这样就可以实现ANR性能 ...
- 我的Android进阶之旅------>Android颜色值(#AARRGGBB)透明度百分比和十六进制对应关系以及计算方法
我的Android进阶之旅-->Android颜色值(RGB)所支持的四种常见形式 透明度百分比和十六进制对应关系表格 透明度 十六进制 100% FF 99% FC 98% FA 97% F7 ...
- 我的Android进阶之旅------>Android中查看应用签名信息
一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...
- 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计
要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...
- 我的Android进阶之旅------> Android为TextView组件中显示的文本添加背景色
通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...
- 我的Android进阶之旅------> Android在TextView中显示图片方法
面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)
在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的 ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)
正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...
随机推荐
- Unix系统编程()改变信号处置:signal
Unix系统提供了两种方法来改变信号处置:signal和sigaction.这篇描述的是signal系统调用,是设置信号处理的原始API,所提供的接口比sigaction简单.另一方面,sigacti ...
- js获取字符串的实际长度并截断实际长度
在项目中有这样一个需求,就是一个很长的字符串,需要截断成几组字符串,而这几组字符串里既包含汉字,又包含字母,下面提供了几种方法 1,获取字符串的长度 function getstrlength(str ...
- 调用半截的div
不能引用jquery: <script src="${rootUrl }js/jquery/jquery.js" type="text/javascript&quo ...
- 嵌入式开发之davinci--- 8148/8168/8127 中的二维图像处理内存tiler 铺瓷砖
http://blog.csdn.net/shanghaiqianlun/article/details/7619603
- 【BZOJ】1609: [Usaco2008 Feb]Eating Together麻烦的聚餐(dp+被坑)
http://www.lydsy.com/JudgeOnline/problem.php?id=1609 首先我不得不说,我被这题坑了.题目前边没有说可以不需要3种牛都有啊!!!!!!!!然后我一直在 ...
- ThinkPHP项目笔记之控制器常用语法
如,有数据表:tmp,以下以此为例. $a = M('Tmp'); $a -> select(); $a -> where(condition)->select(); $a -> ...
- springmvc+mybatis+maven项目框架搭建
项目的目录
- 去除 \ufeff
语言:python 编程工具:pycharm 硬件环境:win10 64位 读取文件过程中发现一个问题:已有记事本文件(非空),转码 UTF-8,复制到pycharm中,在开始位置打印结果会出现 \ ...
- (转)Python中的random模块
Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...
- mybatis 控制台打印出来的sql 执行结果为空 但是将sql放到mysql执行有数据
mybatis中的sql如下 select airln_Cd airlnCd,city_coordinate_j cityCoordinateJ,city_coordinate_w cityCoord ...