问题
I am using download manger to download file in android. But in the case of when tap on "cancel" button from the notification bar , I am unable to get any broadcast.
I have find only two broadcast :
1.DownloadManager.ACTION_DOWNLOAD_COMPLETE
2.DownloadManager.ACTION_NOTIFICTION_CLICKED
Is there any broadcast by Download manager when its cancel ? If not then please give me any solution how to handle it ?
回答1:
DownloadManager
will write information to database when it handle the user download task. So we can check the status of database to know if a task is canceled.
1. use the api from DownloadManager
, polling status periodically
After you enqueue your download task, start the following thread to check.
private static class DownloadQueryThread extends Thread {
private static final String TAG = "DownloadQueryThread";
private final WeakReference<Context> context;
private DownloadManager downloadManager;
private final DownloadManager.Query downloadQuery;
private boolean shouldStopQuery = false;
private boolean downloadComplete = false;
private static final Object LOCK = new Object();
private final BroadcastReceiver downloadCompleteBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
synchronized (LOCK) {
shouldStopQuery = true;
downloadComplete = true;
}
}
}
};
/**
* Create from context and download id
* @param context the application context
* @param queryId the download id from {@link DownloadManager#enqueue(DownloadManager.Request)}
*/
public DownloadQueryThread(Context context, long queryId) {
this.context = new WeakReference<>(context);
this.downloadQuery = new DownloadManager.Query().setFilterById(queryId);
this.downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
}
@Override
public void run() {
super.run();
if (context.get() != null) {
context.get().registerReceiver(downloadCompleteBroadcastReceiver,
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
while (true) {
if (downloadManager != null) {
Cursor cursor = downloadManager.query(downloadQuery);
if (cursor != null && cursor.moveToFirst()) {
Log.d(TAG, "download running");
} else {
shouldStopQuery = true;
}
}
synchronized (LOCK) {
if (shouldStopQuery) {
if (downloadComplete) {
Log.d(TAG, "download complete");
} else {
Log.w(TAG, "download cancel");
}
break;
}
}
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (context.get() != null) {
context.get().unregisterReceiver(downloadCompleteBroadcastReceiver);
}
}
}
2.use ContentObserver
to get notified when database changed
The content uri for download manager should be content://downloads/my_downloads
, we can monitor the changing of this database. When you start a download with a download id, a row will be created content://downloads/my_downloads/{downloadId}
. We can check this cursor to know if this task is canceled or not. If the returned cursor is empty or null, no record found in database, this download task is canceled by user.
// get the download id from DownloadManager#enqueue
getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"),
true, new ContentObserver(null) {
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (uri.toString().matches(".*\\d+$")) {
long changedId = Long.parseLong(uri.getLastPathSegment());
if (changedId == downloadId[0]) {
Log.d(TAG, "onChange: " + uri.toString() + " " + changedId + " " + downloadId[0]);
Cursor cursor = null;
try {
cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
Log.d(TAG, "onChange: running");
} else {
Log.w(TAG, "onChange: cancel");
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
}
});
回答2:
Another solution is to use a file observer at downloads directory
declaration of observer:
private FileObserver fileObserver = new DownloadObserver(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS ).getAbsolutePath(), this);
When you want to start:
fileObserver.startWatching();
When you want to stop:
fileObserver.stopWatching();
The observer class:
public class DownloadObserver extends FileObserver {
public static final String TAG = "DownloadObserver";
Context context;
private static final int flags =
FileObserver.CLOSE_WRITE
| FileObserver.OPEN
| FileObserver.MODIFY
| FileObserver.DELETE
| FileObserver.MOVED_FROM;
public DownloadObserver(String path, Context context) {
super(path, flags);
this.context = context;
}
@Override
public void onEvent(int event, String path) {
if (path == null) {
return;
}
if (event == FileObserver.OPEN || event == FileObserver.CLOSE_WRITE) {
Log.d(TAG, "started or resumed: " + path);
} else if (event == FileObserver.DELETE) {
Log.e(TAG, "File delete:" + path);
//Here is your solution. Download was cancel from notification bar
} else {
//can be used to update download progress using DownloadManager.Query
}
}}
来源:https://stackoverflow.com/questions/48248300/in-download-manager-how-to-get-status-when-its-cancel-from-notification-bar