DownloadManager在INSUFFICIENT_SPACE_ERROR后不发送广播

9

问题

如果缓存目录已满,则尝试执行简单请求时将失败,而不会发送DownloadManager.ACTION_DOWNLOAD_COMPLETE广播。

注意:该问题是一般性的,但在具有限制缓存(/data/data/com.android.providers.downloads/cache)大小的低端设备上可以被大多数复现。

代码

接收器已正确配置,因为当操作成功或因其他原因失败时仍会收到广播。

    DownloadManager.Request request = new DownloadManager.Request(Uri.parse("http://www.apkmirror.com/wp-content/themes/APKMirror/download.php?id=44753"));

    request.setTitle("Facebook");

    DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

    downloadManager.enqueue(request);

期望的解决方案

我对解决具体问题或者更多相关信息感兴趣。
不希望使用需要停止使用DownloadManager或添加WRITE_EXTERNAL_STORAGE权限的解决方案。

日志

当缓存正在充满且最后无法再容纳时,您可以观察到以下日志记录(使用downloadmanager过滤)。

11-08 08:47:06.079 830-14261/? I/DownloadManager: Download 135 starting
11-08 08:47:06.989 830-14261/? W/DownloadManager: Downloads data dir: /data/data/com.android.providers.downloads/cache is running low on space. space available (in bytes): -6994124
11-08 08:47:06.999 830-14261/? I/DownloadManager: discardPurgeableFiles: destination = 2, targetBytes = 10485760
11-08 08:47:06.999 830-14261/? I/DownloadManager: Purged files, freed 0 for 10485760 requested
11-08 08:47:07.309 830-14261/? W/DownloadManager: Aborting request for download 135: not enough free space in the filesystem rooted at: /data/data/com.android.providers.downloads/cache and unable to free any more
11-08 08:47:07.319 830-14261/? I/DownloadManager: Download 135 finished with status INSUFFICIENT_SPACE_ERROR

这里有一个演示项目,可以展示问题。请记住,缓存目录必须在那个时候已经被填满(由于无法清除的项目,根据我的经验,基本上意味着中止下载)。

谢谢@Yvette,我会尝试进一步扩展,理想情况下,我希望能收到下载失败的通知。 - Alex.F
3个回答

3

由于DownloadManager本质上是一个系统ContentProvider,因此您可以向其注册自己的ContentObserver, 因此,当下载提供程序更新时,在INSUFFICIENT_SPACE的情况下,它将选择通知观察者。

final DownloadManager downloadManager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
        context.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"),
                true, new ContentObserver(null) {
                    @Override
                    public void onChange(boolean selfChange) {
                        super.onChange(selfChange);
                        Cursor localCursor = downloadManager.query(
                                new DownloadManager.Query());
                        if (localCursor.getCount() == 0) {
                            localCursor.close();
                        }
                        localCursor.moveToFirst();
                        do {
                            if ((localCursor.getInt(localCursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) & DownloadManager.STATUS_FAILED )!=0) {
                                // Download failed, go see why
                                if (localCursor.getInt(localCursor.getColumnIndex(DownloadManager.COLUMN_REASON)) == DownloadManager.ERROR_INSUFFICIENT_SPACE){
                                    Log.w("DownloadStatus", " Download failed with ERROR_INSUFFICIENT_SPACE");
                                }
                            }
                        }while (localCursor.moveToNext());
                    }
                });

请注意,不要将查询过滤器设置为 DownloadManager.STATUS_FAILED 状态,因为 DownloadManager 奇怪地只将状态介于 400 和 600 之间的状态视为失败状态,但 INSUFFICIENT_SPACE 具有错误代码 198...
android.app.DownloadManager.Request:
Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
 .....
 if ((mStatusFlags & STATUS_FAILED) != 0) {
                    parts.add("(" + statusClause(">=", 400)
                              + " AND " + statusClause("<", 600) + ")");
                }
}

0

您可以通过以下代码获取DownloadManager.STATUS_FAILED的原因,从而接收INSUFFICIENT_SPACE_ERROR广播。

private void DownloadStatus(Cursor cursor, long DownloadId){

        //column for download  status
        int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
        int status = cursor.getInt(columnIndex);
        //column for reason code if the download failed or paused
        int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
        int reason = cursor.getInt(columnReason);
        //get the download filename
        int filenameIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
        String filename = cursor.getString(filenameIndex);

        String statusText = "";
        String reasonText = "";

        switch(status){
            case DownloadManager.STATUS_FAILED:
                statusText = "STATUS_FAILED";
                switch(reason){
                    case DownloadManager.ERROR_CANNOT_RESUME:
                        reasonText = "ERROR_CANNOT_RESUME";
                        break;
                    case DownloadManager.ERROR_DEVICE_NOT_FOUND:
                        reasonText = "ERROR_DEVICE_NOT_FOUND";
                        break;
                    case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
                        reasonText = "ERROR_FILE_ALREADY_EXISTS";
                        break;
                    case DownloadManager.ERROR_FILE_ERROR:
                        reasonText = "ERROR_FILE_ERROR";
                        break;
                    case DownloadManager.ERROR_HTTP_DATA_ERROR:
                        reasonText = "ERROR_HTTP_DATA_ERROR";
                        break;
                    case DownloadManager.ERROR_INSUFFICIENT_SPACE:
                        reasonText = "ERROR_INSUFFICIENT_SPACE";
                        break;
                    case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
                        reasonText = "ERROR_TOO_MANY_REDIRECTS";
                        break;
                    case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
                        reasonText = "ERROR_UNHANDLED_HTTP_CODE";
                        break;
                    case DownloadManager.ERROR_UNKNOWN:
                        reasonText = "ERROR_UNKNOWN";
                        break;
                }
                break;
            case DownloadManager.STATUS_PAUSED:
                statusText = "STATUS_PAUSED";
                switch(reason){
                    case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
                        reasonText = "PAUSED_QUEUED_FOR_WIFI";
                        break;
                    case DownloadManager.PAUSED_UNKNOWN:
                        reasonText = "PAUSED_UNKNOWN";
                        break;
                    case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
                        reasonText = "PAUSED_WAITING_FOR_NETWORK";
                        break;
                    case DownloadManager.PAUSED_WAITING_TO_RETRY:
                        reasonText = "PAUSED_WAITING_TO_RETRY";
                        break;
                }
                break;
            case DownloadManager.STATUS_PENDING:
                statusText = "STATUS_PENDING";
                break;
            case DownloadManager.STATUS_RUNNING:
                statusText = "STATUS_RUNNING";
                break;
            case DownloadManager.STATUS_SUCCESSFUL:
                statusText = "STATUS_SUCCESSFUL";
                reasonText = "Filename:\n" + filename;
                break;
        }
}

1
如果我没有使用DownloadManager.ACTION_DOWNLOAD_COMPLETE接收广播,那么我怎么知道何时检查内容提供程序?你能更具体地说明广播的意图过滤器是什么样子吗? - Alex.F
@Alex.F DownloadManager.STATUS_FAILED:下载管理器状态失败。 - Meesam Abbas
1
@MeesamAbbas 我们只能在BroadcastReceiver的onReceive方法中检查状态。但是真正的问题是当没有空间时,onReceive方法不会被调用。我们只能在日志中看到Finished with status INSUFFICIENT_SPACE_ERROR - Thamilan S
@MeesamAbbas,希望楼主在他的问题中已经清楚地提到了这一点。 - Thamilan S

0
我认为 Gracie 的解决方案需要一些改进,比如注销和检查下载 ID。
如果您不对请求使用任何限制,可以在排队后尝试检查文件大小 - 这不是完美的解决方案:
private static void checkFileSize(Context context, DownloadManager downloadManager, long myDownloadReference, DownloadInfo downloadInfo) {
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(myDownloadReference);

    Handler handler = new Handler();
    handler.postDelayed(() -> {

        Cursor cursor = downloadManager.query(query);
        if (!cursor.moveToFirst()) {
            KLog.i("download list is empty");
            return;
        }

        int size = cursor.getInt(cursor
                .getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
        int status = cursor.getInt(cursor
                .getColumnIndex(DownloadManager.COLUMN_STATUS));
        int reason = cursor.getInt(cursor
                .getColumnIndex(DownloadManager.COLUMN_REASON));

        cursor.close();

        if (reason == DownloadManager.ERROR_INSUFFICIENT_SPACE)
            DownloadedReceiver.handleInsufficientSpace(context, downloadInfo);

    }, 1500);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接