之前开发的一个和第三方合作的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;的更多相关文章

  1. 【我的Android进阶之旅】解决sqlcipher库:java.lang.IllegalStateException: get field slot from row 0 col 0 failed.

    一.背景 最近维护公司的大数据SDK,在大数据SDK里面加入了ANR的监控功能,并将ANR的相关信息通过大数据埋点的方式记录到了数据库中,然后大数据上报的时候上报到大数据平台,这样就可以实现ANR性能 ...

  2. 我的Android进阶之旅------>Android颜色值(#AARRGGBB)透明度百分比和十六进制对应关系以及计算方法

    我的Android进阶之旅-->Android颜色值(RGB)所支持的四种常见形式 透明度百分比和十六进制对应关系表格 透明度 十六进制 100% FF 99% FC 98% FA 97% F7 ...

  3. 我的Android进阶之旅------>Android中查看应用签名信息

    一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...

  4. 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计

    要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...

  5. 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现

    我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...

  6. 我的Android进阶之旅------> Android为TextView组件中显示的文本添加背景色

    通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...

  7. 我的Android进阶之旅------> Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...

  8. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)

    在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的 ...

  9. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)

    正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...

随机推荐

  1. eclipse开发cocos2dx 3.2环境搭建之中的一个: Android C\C++环境搭建(ndk r9d)

    这几天有时间,琢磨一下cocos2dx.cocos2d家族事实上挺庞大的.也有cocos2d-android这样的能够直接用Java语言来开发的,可是cocos2d-android资料相对少一些.并且 ...

  2. 用Linux中man命令查询C函数

    大家都知道在Unix/Linux中有个man命令,可以查询常用的命令,函数.可是对于我们这样只知道用"man 函数名"来查询的人来说,会遇到很多问题,比如: man read,我想 ...

  3. asp.net曲线图

    highcharts的曲线图控件真的很强大,自己研究了下,做了一个简单的,给自己留个备忘,希望能帮到需要的朋友 Dome下载:http://files.cnblogs.com/linyijia/asp ...

  4. 原生js怎么删除一个 div

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. 《javascript征途》学习笔记

    基础 1. 只有函数有作用域 2. 如果在<script src>的src 中设置了src特性,则script元素包含的任意代码就无效了.应该分开放到不同的script块中. 3. 外部j ...

  6. 隐马尔科夫模型(hidden Markov model, HMM)

  7. 第二百七十一节,Tornado框架-CSRF防止跨站post请求伪造

    Tornado框架-CSRF防止跨站post请求伪造 CSRF是什么 CSRF是用来在post请求时做请求验证的,防止跨站post请求伪造 当用户访问一个表单页面时,会自动在表单添加一个隐藏的inpu ...

  8. VBS 处理断开excel数据链接格式,只保留值

    最近有个项目是将一个excel压缩之后发给客户,但是由于excel数据过大,即使压缩之后仍然接近5M,因为是大批量发送数据,所以非常慢.急需要将EXCEL数据压缩. 后来我想到一个办法,就excel数 ...

  9. YII2与Thinkphp整合阿里云OSS

    前言: 如果上传的文件都和网站程序源代码放在一起:那是有相当多的弊端的: 1:静态文件会占用大量带宽: 2:服务器的成本略高: 常规的做法是把php源代码放到一台服务器上:图片等静态文件放在另一台服务 ...

  10. 系统管理模块_岗位管理_改进_使用ModelDroven方案_套用美工写好的页面效果_添加功能与修改功能使用同一个页面

    改进_使用ModelDroven方案 @Controller @Scope("prototype") public class RoleAction extends ActionS ...