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" );
        }

版权声明:本文为baimiyishu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/baimiyishu/p/15013627.html