DownloaderManager遇到的那些crash坑

DownloaderManager作爲一個很好用的系統級別API用作下載文件很方便,我們這篇文章不介紹如何使用它,我們來說說在使用過程中出現的幾個crash,如果出現了這幾個crash,尤其是第三個,那麼恭喜你,可以去買彩票了,嘿嘿

  • 首先來說第一個問題 Fatal Exception: java.lang.UnsupportedOperationException Cannot update URI: content://downloads/my_downloads/-1, 這個問題是因爲我們在使用DownloaderManager進行remove操作的時候,參數id爲-1導致的
  • 解決辦法:remove之前記得判斷一個id是否大於0即可

  • 第二個crash,Fatal Exception: java.lang.IllegalArgumentException Unknown URL content://downloads/my_downloads, android.content.ContentResolver.insert (ContentResolver.java:1541), android.app.DownloadManager.enqueue (DownloadManager.java:1504),如果出現這個crash,說明用戶手機中DownloaderManager被disable了。
  • 解決辦法:在測試過程中我們可以通過adb shell pm enable com.android.providers.downloadsenable;或者使用adb shell pm disable com.android.providers.downloadsdisable;google play的做法是在進入應用的時候檢查用戶是否disable了DownloaderManager,如果disable了,會彈出一個dialog提示用戶(如下圖所示):
    在這裏插入圖片描述
    • 如果用戶點擊同意就enable ·DownloaderManager·進入應用,點擊取消就退出應用,不讓用戶使用;我們可以參考這個做法,如果應用是系統級應用,可以申請權限CHANGE_COMPONENT_ENABLED_STATE,調用PackageManager.setApplicationEnabledSetting來enable, 或者引導用戶開啓。
    public static void startActivityToOpenDownloadManager(Context context) {
        Intent downloadIntent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        downloadIntent.setData(Uri.parse("package:com.android.providers.downloads"));
        downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(downloadIntent);
    }
    

第三個crash是Fatal Exception: java.lang.NullPointerException Attempt to invoke virtual method java.lang.String android.net.Uri.getLastPathSegment()?on a null object reference android.app.DownloadManager.enqueue (DownloadManager.java:1026),如果出現這個crash,你真的可以去買彩票了。

  • 分析:通過查看源碼得知是在DownloaderManager.enqueue出現的crash,我們查看源碼:
     public long enqueue(Request request) {
            ContentValues values = request.toContentValues(mPackageName);
            Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
            long id = Long.parseLong(downloadUri.getLastPathSegment());
            return id;
    }
    
        public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
                @Nullable ContentValues values) {
        Preconditions.checkNotNull(url, "url");
    
        try {
            if (mWrapped != null) return mWrapped.insert(url, values);
        } catch (RemoteException e) {
            return null;
        }
    
        IContentProvider provider = acquireProvider(url);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URL " + url);
        }
        try {
            long startTime = SystemClock.uptimeMillis();
            Uri createdRow = provider.insert(mPackageName, url, values);
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
            return createdRow;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            releaseProvider(provider);
        }
    }
    
  • 從上面的代碼中可以看出是因爲insert返回了null,所以導致後面(downloadUri.getLastPathSegment()出現了空指針異常,而能出現null的情況都是拋出了RemoteException,官網對這個異常的描述是Parent exception for all Binder remote-invocation errors,說明這個異常是和binder機制相關的,那麼基本可以確定是DownloadManager被disable掉了,那麼解決辦法自然和第二個crash一樣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章