【我的Android进阶之旅】 解决bug: Expected file scheme in URI: content://downloads/my_downloads/12

一、错误描述

今天测试MM用HTC手机测试某个模块的时候crash了,抓log后发现是使用DownloadManager下载apk安装包然后自动安装的时候,抛了异常:java.lang.IllegalArgumentException: Expected file scheme in URI: content://downloads/my_downloads/12

具体crash错误信息如下所示:


11-30 09:24:21.933 28279 28279 E AndroidRuntime: FATAL EXCEPTION: main
11-30 09:24:21.933 28279 28279 E AndroidRuntime: Process: com.xtc.watch, PID: 28279
11-30 09:24:21.933 28279 28279 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.DOWNLOAD_COMPLETE flg=0x10 pkg=com.xtc.watch (has extras) } in
 com.xtc.watch.service.compatible.VersionCompatibleUpdateService$DownloadCompleteReceiver@33fa7ec
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:934)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.os.Handler.handleCallback(Handler.java:739)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:95)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:168)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:5885)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
11-30 09:24:21.933 28279 28279 E AndroidRuntime: Caused by: java.lang.IllegalArgumentException: Expected file scheme in URI: content://downloads/my_downloads/12
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at java.io.File.checkURI(File.java:223)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at java.io.File.<init>(File.java:175)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at com.xtc.watch.service.compatible.VersionCompatibleUpdateService.a(Unknown Source)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at com.xtc.watch.service.compatible.VersionCompatibleUpdateService.a(Unknown Source)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at com.xtc.watch.service.compatible.VersionCompatibleUpdateService$DownloadCompleteReceiver.onReceive(Unknown Source)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:915)
11-30 09:24:21.933 28279 28279 E AndroidRuntime:        ... 7 more
11-30 09:24:21.939  1785  3503 E ActivityManager: App crashed! Process: com.xtc.watch

二、错误分析

进入File.java查看代码,

    /**
     * Constructs a new File using the path of the specified URI. {@code uri}
     * needs to be an absolute and hierarchical Unified Resource Identifier with
     * file scheme and non-empty path component, but with undefined authority,
     * query or fragment components.
     *
     * @param uri
     *            the Unified Resource Identifier that is used to construct this
     *            file.
     * @throws IllegalArgumentException
     *             if {@code uri} does not comply with the conditions above.
     * @see #toURI
     * @see java.net.URI
     */
    public File(URI uri) {
        // check pre-conditions
        checkURI(uri);
        this.path = fixSlashes(uri.getPath());
    }

checkURI(URI uri)的源代码如下:

private static void checkURI(URI uri) {
        if (!uri.isAbsolute()) {
            throw new IllegalArgumentException("URI is not absolute: " + uri);
        } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
            throw new IllegalArgumentException("URI is not hierarchical: " + uri);
        }
        if (!"file".equals(uri.getScheme())) {
            throw new IllegalArgumentException("Expected file scheme in URI: " + uri);
        }
        String rawPath = uri.getRawPath();
        if (rawPath == null || rawPath.isEmpty()) {
            throw new IllegalArgumentException("Expected non-empty path in URI: " + uri);
        }
        if (uri.getRawAuthority() != null) {
            throw new IllegalArgumentException("Found authority in URI: " + uri);
        }
        if (uri.getRawQuery() != null) {
            throw new IllegalArgumentException("Found query in URI: " + uri);
        }
        if (uri.getRawFragment() != null) {
            throw new IllegalArgumentException("Found fragment in URI: " + uri);
        }
    }

原来就是下面这一段代码抛出的异常,如果uri不是以file开头的就抛异常IllegalArgumentException(“Expected file scheme in URI: ” + uri),

        if (!"file".equals(uri.getScheme())) {
            throw new IllegalArgumentException("Expected file scheme in URI: " + uri);
        }

而我们的uri 是通过下面代码获取而来的

Uri downloadFileUri = manager.getUriForDownloadedFile(downId);
File file = new File(new URI(downloadFileUri.toString()));

得到的uri信息为

content://downloads/my_downloads/12

因此就抛了该异常出来。

getUriForDownloadedFile(long id)源代码如下:

 /**
     * Returns the {@link Uri} of the given downloaded file id, if the file is
     * downloaded successfully. Otherwise, null is returned.
     *<p>
     * If the specified downloaded file is in external storage (for example, /sdcard dir),
     * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
     * to the filepath on sdcard.
     *
     * @param id the id of the downloaded file.
     * @return the {@link Uri} of the given downloaded file id, if download was successful. null
     * otherwise.
     */
    public Uri getUriForDownloadedFile(long id) {
        // to check if the file is in cache, get its destination from the database
        Query query = new Query().setFilterById(id);
        Cursor cursor = null;
        try {
            cursor = query(query);
            if (cursor == null) {
                return null;
            }
            if (cursor.moveToFirst()) {
                int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
                if (DownloadManager.STATUS_SUCCESSFUL == status) {
                    int indx = cursor.getColumnIndexOrThrow(
                            Downloads.Impl.COLUMN_DESTINATION);
                    int destination = cursor.getInt(indx);
                    // TODO: if we ever add API to DownloadManager to let the caller specify
                    // non-external storage for a downloaded file, then the following code
                    // should also check for that destination.
                    if (destination == Downloads.Impl.DESTINATION_CACHE_PARTITION ||
                            destination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION ||
                            destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING ||
                            destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) {
                        // return private uri
                        return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, id);
                    } else {
                        // return public uri
                        String path = cursor.getString(
                                cursor.getColumnIndexOrThrow(COLUMN_LOCAL_FILENAME));
                        return Uri.fromFile(new File(path));
                    }
                }
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        // downloaded file not found or its status is not 'successfully completed'
        return null;
    }

三、错误解决

将之前查找下载好的apk文件的代码


Uri downloadFileUri = manager.getUriForDownloadedFile(downId);

File file = new File(new URI(downloadFileUri.toString()));

改为通过downId来查询DownloadManager下载的数据库的记录,然后查找本地文件的路径,如下所示:


Cursor c = manager.query(new DownloadManager.Query().setFilterById(downId));
if(c != null){
    c.moveToFirst();
    int fileNameIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
    String fileName = c.getString(fileNameIdx);
    File file  = new File(fileName);
    LogUtil.d(TAG, "安装文件:" + file.getAbsolutePath());
    c.close();
}

安装apk的代码由


//自动安装apk
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);

改为


//自动安装apk
Intent install = new Intent(Intent.ACTION_VIEW);
//install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");
install.setDataAndType(Uri.parse("file://" + fileName.toString()), "application/vnd.android.package-archive");
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);

这样通过查询本地真实的下载好apk的真实本地路径,然后再进行安装的话就不会报异常了。

参考文章:
http://blog.csdn.net/q445697127/article/details/40537945

http://www.xuebuyuan.com/2163407.html

http://www.2cto.com/kf/201502/376975.html


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

时间: 2024-10-28 09:58:53

【我的Android进阶之旅】 解决bug: Expected file scheme in URI: content://downloads/my_downloads/12的相关文章

我的Android进阶之旅------&amp;gt;解决Jackson等第三方转换Json的开发包在开启混淆后转换的实体类数据都是null的bug

1.错误描述 今天测试人员提了一个bug,说使用我们的app出现了闪退的bug,后来通过debug断点调试,发现我们的app转换服务器发送过来的json数据后,都是为null.而之前已经提测快一个月的功能,一直都是稳定的,为什么现在会报java.lang.NullPointerException. 2.错误原因 原来我提测了一个月的APP版本一直没有打开混淆开关,而出问题的这个APP版本在即将要发布出去的时候打开了混淆开关.这样的话,我那些要通过转换json数据为bean实体类,因为没有在pro

我的Android进阶之旅------&amp;gt;Android字符串资源中的单引号问题error: Apostrophe not preceded by 的解决办法

刚刚在string字符串资源文件中,写了一个单引号,报错了,错误代码如下 error: Apostrophe not preceded by \ (in OuyangPeng's blog ) 资源文件如下: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="ouyang">OuyangPeng's blog </string

我的Android进阶之旅------&amp;gt;如何解决Android 5.0中出现的警告: Service Intent must be explicit:

我的Android进阶之旅-->如何解决Android 5.0中出现的警告: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.xtc.kuwo.watch.MUSIC_PLAY_SERVICE (has extras) } 1.错误描述 今天在Android4.4 的小米4手机上运行我的程序的时候没有报错,而在Android 5.1的华为P7上运行我的程序的时候报了以下的错

我的Android进阶之旅------&amp;gt;Java字符串格式化方法String.format()格式化float型时小数点变成逗号问题

    今天接到一个波兰的客户说有个APP在英文状态下一切运行正常,但是当系统语言切换到波兰语言的时候,程序奔溃了.好吧,又是我来维护.     好吧,先把系统语言切换到波兰语,切换到波兰语的方法查看文章 我的Android进阶之旅------>Android[设置]-[语言和输入法]-[语言]列表中找到相应语言所对应的列表项   地址:http://blog.csdn.net/ouyang_peng/article/details/50209789 ======================

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之状态数据模型(三)

对于游戏玩家而言,游戏界面上看到的"元素"千变万化:但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已.因此建立游戏的状态数据模型是实现游戏逻辑的重要步骤. 1.定义数据模型 连连看的界面是一个NxM的"网格",每个网格上显示一张图片.而这个网格只需要一个二维数组来定义即可,而每个网格上所显示的图片,对于底层数据模型来说,不同的图片对于着不同的数值即可. 对于上图所示的数据模型,只要让数值为0的网格上不绘制图片,其他数值的网

我的Android进阶之旅------&amp;gt;介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程,因此今天百度了一下gif动画的制作工具,找到了这款不错的软件GifCam.然后我使用该软件将动画制作成gif动画,然后更新了上一篇文章上传了新制作的gif动画,使博客的说明效果更佳. 该软件的界面如下所示: 该软件的操作步骤如下: 1.拖动 GifCam 标题栏,改变其位置,并调整 GifCam 窗口大

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之开发游戏界面(二)

连连看的游戏界面十分简单,大致可以分为两个区域: 游戏主界面区 控制按钮和数据显示区 1.开发界面布局 本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定义组件,下面是一个水平排列的LinearLayout. 下面是本程序的布局文件:/res/layout/main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)

正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piece对象时,程序会直接调用ImageUtil的getPlayImages()方法去获取图片,该方法会随机从res/drawable目录中取得N张图片. 下面是res/drawable目录视图: 为了让getPlayImages()方法能随机从res/drawable目录中取得N张图片,具体实现分为以下几步: 通

我的Android进阶之旅------&amp;gt; Android为TextView组件中显示的文本添加背景色

通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article/details/46916963)      我们学会了在TextView中显示图片的方法,现在我们来学习如何为TextView组件中显示的文本添加背景色.要求完成的样子如图所示: 首先来学习使用BackgroundColorSpan对象设置文字背景色,代码如下: TextView textView=(