downloadmanager時Android系統下載器,使用系統下載器可以避免用stream流讀入記憶體可能導致的記憶體溢位問題。以下為downloadmanager初始化部分。apkurl為下載網路路徑。Environment.DIRECTORY_DOWNLOADS 為系統的下載路徑。即下載至外部儲存。
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
String apkUrl = "https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk";
Uri resource = Uri.parse(apkUrl);
DownloadManager.Request request = new DownloadManager.Request(resource);
//下載的本地路徑,表示設定下載地址為SD卡的Download資料夾,檔名為mobileqq_android.apk。
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "mobileqq_android.apk");
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setVisibleInDownloadsUi(true);
request.setDescription("xiazaizhong");
//end 一些非必要的設定
id = mDownloadManager.enqueue(request);
//下載後的本地uri
uri = mDownloadManager.getUriForDownloadedFile(id);
enqueue方法為新增到下載佇列,同時返回的id用於contentobserver監聽下載進度.下載進度監聽程式碼如下:
private DownloadContentObserver observer = new DownloadContentObserver();
class DownloadContentObserver extends ContentObserver {
public DownloadContentObserver() {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
// updateView();
if (scheduledExecutorService != null) {
scheduledExecutorService.scheduleWithFixedDelay(runnable, 0, 3, TimeUnit.SECONDS);
}
}
}
public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
public void updateView() {
int[] bytesAndStatus = getBytesAndStatus(id);
int currentSize = bytesAndStatus[0];//當前大小
int totalSize = bytesAndStatus[1];//總大小
int status = bytesAndStatus[2];//下載狀態 1開始 2下載中 8下載完成
Message.obtain(handler, 0, currentSize, totalSize, status).sendToTarget();
}
public int[] getBytesAndStatus(long downloadId) {
int[] bytesAndStatus = new int[]{-1, -1, 0};
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
Cursor c = null;
try {
c = mDownloadManager.query(query);
if (c != null && c.moveToFirst()) {
bytesAndStatus[0] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
bytesAndStatus[1] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
bytesAndStatus[2] = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
}
} finally {
if (c != null) {
c.close();
}
}
return bytesAndStatus;
}
設定 DownloadContentObserver類監聽下載進度,可在其重寫的 onchange方法中更新UI,即updataView方法,但此會返回大量資料,在下載量大時可使用ScheduledExecutorService 設定定時任務,註冊定時任務設定間隔時間查詢進度,downloadcontentobserver需要在onresume 和 ondestroy方法中註冊和登出程式碼在下,getBytesAndStatus方法獲取佇列中陣列當前下載的進度 包括當前大小總大小,下載狀態等。
登出和註冊downloadcontentobserver的程式碼
private static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");
getContentResolver().registerContentObserver(CONTENT_URI, true, observer);
getContentResolver().unregisterContentObserver(observer);
定時任務中執行的runable 為更新UI的 updateView方法
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
updateView();
} catch (Exception e) {
e.printStackTrace();
}
}
};
最後即是updateView方法中傳送message的handeler程式碼,message可傳入兩個bundle引數和一個object物件。從handler中取出可以更新UI 或邏輯操作了,注意宣告handler時傳入了 mainlooper,這樣不用再特地主執行緒中更新UI,測試中下載完成時狀態碼為8,具體使用時可再次測試。下載結束後可將定時任務關閉置空。
private Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull @NotNull Message msg) {
super.handleMessage(msg);
if (scheduledExecutorService != null) {
int currentSize = msg.arg1;
int totalSize = msg.arg2;
Object object = msg.obj;
tvDownload.setText(String.valueOf(((float) (currentSize / totalSize)) * 100));
if ((Integer) object == 8) {
scheduledExecutorService.shutdownNow();
scheduledExecutorService = null;
Toast.makeText(ControlerActivity.this, "下載完成", Toast.LENGTH_SHORT).show();
}
Log.e(TAG, "handleMessage:" + currentSize + " " + totalSize + " " + object.toString());
}
}
};
最後測試下載的本地的uri是否正確,檔案下載是否成功 Environment.getExternalStoragePublicDirectory獲取外部儲存的下載路徑。還有下載完成點選通知跳轉和下載完成監聽功能不再詳述。
File file=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"/mobileqq_android.apk");
if (file.exists()) {
Log.e(TAG, "exists yes"+file.length());
}else {
Log.e(TAG, "exists no" );
}