DownloadManager使用及进度更新

1. Android SD存储相关

1) 检查SD状态

 

if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    Toast.makeText(MainActivity.this, "无法操作SD卡", Toast.LENGTH_LONG).show();
    return true;
}

 

 

2) 获取SD下载目录

 

String downloadDirPath = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();

 

 

2. DownloadManager

1) 配置权限

 

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

 

2) 获取实例

 

DownloadManager downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

 

 

3) 通过DownloadManager.Request设置下载请求信息

 

//downloadUrl为下载地址
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));

//设置文件下载目录和文件名
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "test.apk");

//设置下载中通知栏提示的标题
request.setTitle("test apk");

//设置下载中通知栏提示的介绍
request.setDescription("测试下载中");

/*
表示下载进行中和下载完成的通知栏是否显示,默认只显示下载中通知,
VISIBILITY_HIDDEN表示不显示任何通知栏提示,
这个需要在AndroidMainfest中添加权限android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
*/
//request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

/*
表示下载允许的网络类型,默认在任何网络下都允许下载,
有NETWORK_MOBILE、NETWORK_WIFI、NETWORK_BLUETOOTH三种及其组合可供选择;
如果只允许wifi下载,而当前网络为3g,则下载会等待
*/
//request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);

//移动网络情况下是否允许漫游
//request.setAllowedOverRoaming(true);

//表示允许MediaScanner扫描到这个文件,默认不允许
//request.allowScanningByMediaScanner();

/*
设置下载文件的mineType,
因为下载管理Ui中点击某个已下载完成文件及下载完成点击通知栏提示都会根据mimeType去打开文件,
所以我们可以利用这个属性。比如上面设置了mimeType为application/package.name,
我们可以同时设置某个Activity的intent-filter为application/package.name,用于响应点击的打开文件
*/
//request.setMimeType("application/package.name");

//添加请求下载的网络链接的http头,比如User-Agent,gzip压缩等
//request.addRequestHeader(String header, String value);

 

 

4) 发起下载请求

 

/*
调用downloadManager的enqueue接口进行下载,
返回唯一的downloadId用于下载状态查询和下载完成监听
*/
long downloadId = downloadManager.enqueue(request);

 

 

3. 查询下载状态

DownloadManager.Query用来查询下载信息

 

//setFilterById根据下载id进行过滤
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
Cursor cursor = null;
try {
	cursor = downloadManager.query(query);
	if (cursor != null && cursor.moveToFirst()) {
		downloadedBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
		totalBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
		status = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
	}
} finally {
	if (cursor != null) {
		cursor.close();
	}
}

 

 

4. 连续性地更新下载进度

1) 方法一:注册ContentObserver,监听下载状态,每次变化都会触发onChange

private ContentObserver downloadObserver = new ContentObserver(mHandler) {
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);

        //TODO
        //此处可以通知handle去查询下载状态
    }
};

@Override
protected void onResume() {
	super.onResume();
	//注册ContentObserver
	getContentResolver().registerContentObserver(
			Uri.parse("content://downloads/my_downloads"), true, downloadObserver);
}

@Override
protected void onPause() {
	super.onPause();
	getContentResolver().unregisterContentObserver(downloadObserver);
}

 

2) 方法二:通过ScheduledExecutorService轮询

a) ScheduledExecutorService相关

① 接口scheduleAtFixedRate原型定义及参数说明

/*
command:执行线程
initialDelay:初始化延时
period:两次开始执行最小间隔时间
unit:计时单位
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,  
            long initialDelay,  
            long period,  
            TimeUnit unit);  

 

注:If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

即当执行任务的时间大于我们指定的间隔时间时,它并不会在指定间隔时开辟一个新的线程并发执行这个任务,而是等待该线程执行完毕。

 

②关于任务的取消和重用

//get reference to the future
Future<?> future = service.scheduleAtFixedRate(runnable, INITIAL_DELAY, INTERVAL, TimeUnit.SECONDS)
//cancel instead of shutdown
future.cancel(true);
//schedule again (reuse)
future = service.scheduleAtFixedRate(runnable, INITIAL_DELAY, INTERVAL, TimeUnit.SECONDS)
//shutdown when you don't need to reuse the service anymore
service.shutdown()

 

b) 具体实现

ScheduledExecutorService scheduledExecutorService;
Future<?> future;

//下载的文件存储名
String downloadFilePath = Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
        + "/test.apk";

File downFile = new File(downloadFilePath);
long fileTotalSize;

//每过100ms通知handler去查询下载状态
future = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        Message msg = mHandler.obtainMessage();
        msg.what = QUERY;
        mHandler.sendMessage(msg);
    }
}, 0, 100, TimeUnit.MILLISECONDS);


private Handler mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
           
            case QUERY:
                Cursor cursor = downloadManager.query(query);

                if (cursor != null && cursor.moveToFirst()) {
                	//此处直接查询文件大小
                    long downSize = downFile.length();

                    //获取文件下载总大小
                    fileTotalSize = cursor.getLong(cursor.getColumnIndex(
                            DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                    cursor.close();

                    Log.w(TAG, "downloaded size: " + downSize);
                    Log.w(TAG, "total size: " + fileTotalSize);

                    if (fileTotalSize != 0) {
                        int percentage = (int) (downSize * 100 / fileTotalSize);

                        statusBar.setProgress(percentage);
                        statusText.setText(percentage + "%");
                    }

                    //终止轮询task
                    if (fileTotalSize == downSize)
                        future.cancel(true);
                }
        }
        return true;
    }
});

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    scheduledExecutorService = Executors.newScheduledThreadPool(1);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (future != null && !future.isCancelled())
        future.cancel(true);

    if (scheduledExecutorService != null &&
            !scheduledExecutorService.isShutdown())
        scheduledExecutorService.shutdown();
}

 

5. 获取DownloadManager下载完成的推送信息

下载完成后,DownloadManager会发出DownloadManager.ACTION_DOWNLOAD_COMPLETE这个广播,并传递downloadId作为参数。通过接受广播我们可以打开对下载完成的内容进行操作。

BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

        if (completeDownloadId == downloadId) {
            Log.w(TAG, "download complete");

            statusBar.setProgress(100);
            statusText.setText("100%");
        }
    }
};

@Override
protected void onResume() {
    super.onResume();

    /** 注册下载完成接收广播 **/
    registerReceiver(downloadCompleteReceiver,
            new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}

@Override
protected void onPause() {
    super.onPause();
    
    unregisterReceiver(downloadCompleteReceiver);
}

 

6. Refer:

Android系统下载管理DownloadManager功能介绍及使用示例

ScheduledExecutorService start stop several times

 

 

你可能感兴趣的:(progress,DownloadManager)