简介:
DownLoadManager是一个系统服务,用于处理长时间下载任务,DownLoadManager会在后台处理HTTP交互和重试下载失败或跨连接启动系统,DownloadManager是用service更新进度,用广播监听下载完成和点击事件。DownLoadManager中有两个内部类:DownloadManager.Query和DownloadManager.Request。前者用于查询下载,后者用于设置一些效果设置。-
DownloadManager.Request类的常用方法:
addRequestHeader(String header, String value):添加一个请求头
setAllowedNetworkTypes(int flags):设置下载时所使用的网络类型,提供的常量有:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。
setAllowedOverRoaming(boolean allowed):是否允许漫游
setDescription(CharSequence description):设置下载的描述信息
setDestinationInExternalFilesDir(Context context, String dirType, String subPath):设置下载文件外部存储目录
setDestinationUri(Uri uri):设置下载目标的URI
setMimeType(String mimeType):设置MIME类型
setShowRunningNotification(boolean show):设置是否显示下载进度提示
setTitle(CharSequence title):设置下载时Notification的标题
setVisibleInDownloadsUi(boolean isVisible):设置是否现在下载界面
以上的各个方法,如果不设置的话就是默认的。 -
有关暂停的一些状态,同样COLUMN_REASON字段的值定义常量有:
int PAUSED_QUEUED_FOR_WIFI 由于移动网络数据问题,等待WiFi连接能用后再重新进入下载队列
int PAUSED_UNKNOWN 未知原因导致了任务下载的暂停
int PAUSED_WAITING_FOR_NETWORK 可能由于没有网络连接而无法下载,等待有可用的网络连接恢复
int PAUSED_WAITING_TO_RETRY 由于重重原因导致下载暂停,等待重试 -
DownloadManager.Query类
DownloadManager.Query类只有两个方法:setFilterById(long… ids)根据任务Id查找和setFilterByStatus(int flags) 根据任务状态查找。但是定义了很多常量:下载状态常量:
int STATUS_FAILED 失败
int STATUS_PAUSED 暂停
int STATUS_PENDING 等待将开始
int STATUS_RUNNING 正在处理中
int STATUS_SUCCESSFUL 已经下载成功
DownloadManager.Query类查询返回的是一个Cursor游标,上面描述的状态就会保存在COLUMN_STATUS 字段中。下载状态会以广播的形式通知,Android系统定义的Action有:
ACTION_DOWNLOAD_COMPLETE下载完成的动作。
ACTION_NOTIFICATION_CLICKED 当用户单击notification中下载管理的某项时触发。
ACTION_VIEW_DOWNLOADS 查看下载项
对于未完成的状态,我们查找COLUMN_REASON字段,定义的常量有:
int ERROR_CANNOT_RESUME 不能够继续,由于一些其他原因。
int ERROR_DEVICE_NOT_FOUND 外部存储设备没有找到,比如SD卡没有插入。
int ERROR_FILE_ALREADY_EXISTS 要下载的文件已经存在了,要想重新下载需要删除原来的文件
int ERROR_FILE_ERROR 可能由于SD卡原因导致了文件错误。
int ERROR_HTTP_DATA_ERROR 在Http传输过程中出现了问题。
int ERROR_INSUFFICIENT_SPACE 由于SD卡空间不足造成的
int ERROR_TOO_MANY_REDIRECTS 这个Http有太多的重定向,导致无法正常下载
int ERROR_UNHANDLED_HTTP_CODE 无法获取http出错的原因,比如说远程服务器没有响应。
int ERROR_UNKNOWN 未知的错误类型. -
有关暂停的一些状态,同样COLUMN_REASON字段的值定义常量有:
int PAUSED_QUEUED_FOR_WIFI 由于移动网络数据问题,等待WiFi连接能用后再重新进入下载队列
int PAUSED_UNKNOWN 未知原因导致了任务下载的暂停
int PAUSED_WAITING_FOR_NETWORK 可能由于没有网络连接而无法下载,等待有可用的网络连接恢复
int PAUSED_WAITING_TO_RETRY 由于重重原因导致下载暂停,等待重试 DownLoadManager的下载及进度监听例子:
service工具类如下:
public class DownloadServise extends Service {
private static final String TAG = DownloadServise.class.getSimpleName();
public static final int HANDLE_DOWNLOAD = 0x001;
public static final String BUNDLE_KEY_DOWNLOAD_URL = "download_url";
public static final float UNBIND_SERVICE = 2.0F;
private Activity activity;
private DownloadBinder binder;
private DownloadManager downloadManager;
private DownloadChangeObserver downloadObserver;
private BroadcastReceiver downLoadBroadcast;
private ScheduledExecutorService scheduledExecutorService;
//下载任务ID
private long downloadId;
private String downloadUrl;
public static OnProgressListener onProgressListener;
@SuppressLint("HandlerLeak") public Handler downLoadHandler = new Handler() { //主线程的handler
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (onProgressListener != null && HANDLE_DOWNLOAD == msg.what) {
//被除数可以为0,除数必须大于0
if (msg.arg1 >= 0 && msg.arg2 > 0) {
onProgressListener.onProgress(msg.arg1 / (float) msg.arg2);
}
}
}
};
private Runnable progressRunnable = new Runnable() {
@Override
public void run() {
updateProgress();
}
};
@Override
public void onCreate() {
super.onCreate();
binder = new DownloadBinder();
}
@Override
public IBinder onBind(Intent intent) {
downloadUrl = intent.getStringExtra(BUNDLE_KEY_DOWNLOAD_URL);
downloadApk(downloadUrl);
return binder;
}
/**
* 下载最新APK
*/
private void downloadApk(String url) {
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
downloadObserver = new DownloadChangeObserver();
registerContentObserver();
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
//request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "my.apk");
request.setDestinationInExternalFilesDir(this, null, "my.apk");
request.setTitle("title");
//request.setDescription("下载中通知栏提示");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
//request.setMimeType("application/cn.trinea.download.file"); //用于响应点击的打开文件
request.setVisibleInDownloadsUi(true); //显示下载界面
request.allowScanningByMediaScanner(); //准许被系统扫描到
downloadId = downloadManager.enqueue(request);
registerBroadcast(); //下载成功和点击通知栏动作监听
}
/**
* 注册广播
*/
private void registerBroadcast() {
/**注册service 广播 1.任务完成时 2.进行中的任务被点击*/
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
registerReceiver(downLoadBroadcast = new DownLoadBroadcast(), intentFilter);
}
/**
* 注销广播
*/
private void unregisterBroadcast() {
if (downLoadBroadcast != null) {
unregisterReceiver(downLoadBroadcast);
downLoadBroadcast = null;
}
}
/**
* 注册ContentObserver
*/
private void registerContentObserver() {
/** observer download change **/
if (downloadObserver != null) {
getContentResolver().registerContentObserver(
Uri.parse("content://downloads/my_downloads"), false, downloadObserver);
}
}
/**
* 注销ContentObserver
*/
private void unregisterContentObserver() {
if (downloadObserver != null) {
getContentResolver().unregisterContentObserver(downloadObserver);
}
}
/**
* 关闭定时器,线程等操作
*/
private void close() {
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
scheduledExecutorService.shutdown();
}
if (downLoadHandler != null) {
downLoadHandler.removeCallbacksAndMessages(null);
}
}
/**
* 发送Handler消息更新进度和状态
* 将查询结果从子线程中发往主线程(handler方式),以防止ANR
*/
private void updateProgress() {
int[] bytesAndStatus = getBytesAndStatus(downloadId);
downLoadHandler.sendMessage(downLoadHandler.obtainMessage(HANDLE_DOWNLOAD, bytesAndStatus[0], bytesAndStatus[1], bytesAndStatus[2]));
}
/**
* 通过query查询下载状态,包括已下载数据大小,总大小,下载状态
*
* @param downloadId
* @return
*/
private int[] getBytesAndStatus(long downloadId) {
int[] bytesAndStatus = new int[]{
-1, -1, 0
};
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
Cursor cursor = null;
try {
cursor = downloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
//已经下载文件大小
bytesAndStatus[0] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//下载文件的总大小
bytesAndStatus[1] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
//下载状态
bytesAndStatus[2] = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return bytesAndStatus;
}
/**
* 绑定此DownloadService的Activity实例
*
* @param activity
*/
public void setTargetActivity(Activity activity) {
this.activity = activity;
}
/**
* 接受下载完成广播
*/
private class DownLoadBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
switch (intent.getAction()) {
case DownloadManager.ACTION_DOWNLOAD_COMPLETE:
if (downloadId == downId && downId != -1 && downloadManager != null) {
Uri downIdUri = downloadManager.getUriForDownloadedFile(downloadId);
close();
if (downIdUri != null) {
SPTools.put(Constant.SP_DOWNLOAD_PATH, downIdUri.getPath());
LogUtil.showLog(TAG, "广播监听下载完成,APK存储路径为 :" + downIdUri.getPath());
installApk(context, downIdUri);
}
if (onProgressListener != null) {
onProgressListener.onProgress(UNBIND_SERVICE);
}
}
break;
case DownloadManager.ACTION_NOTIFICATION_CLICKED:
ToastUitl.showToast("我被点击啦!");
break;
}
}
}
/**
* 监听下载进度
*/
private class DownloadChangeObserver extends ContentObserver {
public DownloadChangeObserver() {
super(downLoadHandler);
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
}
/**
* 当所监听的Uri发生改变时,就会回调此方法
* @param selfChange 此值意义不大, 一般情况下该回调值false
*/
@Override
public void onChange(boolean selfChange) {
scheduledExecutorService.scheduleAtFixedRate(progressRunnable, 0, 1, TimeUnit.SECONDS); //在子线程中查询
}
}
public class DownloadBinder extends Binder {
/**
* 返回当前服务的实例
* @return
*/
public DownloadServise getService() {
return DownloadServise.this;
}
}
public interface OnProgressListener {
/**
* 下载进度
* @param fraction 已下载/总大小
*/
void onProgress(float fraction);
}
/**
* 对外开发的方法
* @param onProgressListener
*/
public void setOnProgressListener(OnProgressListener onProgressListener) {
DownloadServise.onProgressListener = onProgressListener;
}
public static void installApk(Context context, Uri apkPath) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apkPath, "application/vnd.android.package-archive");
context.startActivity(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterBroadcast();
unregisterContentObserver();
}
}
绑定服务开始下载代码:
private ProgressDialog progress;
private boolean isBindService;
private ServiceConnection conn = new ServiceConnection() { //通过ServiceConnection间接可以拿到某项服务对象
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
DownloadServise.DownloadBinder binder = (DownloadServise.DownloadBinder) service;
DownloadServise downloadServise = binder.getService();
//接口回调,下载进度
downloadServise.setOnProgressListener(new DownloadServise.OnProgressListener() {
@Override
public void onProgress(float fraction) {
progress.setProgress((int)(fraction * 100));
//判断是否真的下载完成进行安装了,以及是否注册绑定过服务
if (fraction == downloadServise.UNBIND_SERVICE && isBindService) {
progress.setProgress(100);
progress.dismiss();
unbindService(conn);
isBindService = false;
}
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void initProgressBar() {
progress = new ProgressDialog(this);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(1);
progress.setCancelable(false);
progress.setCanceledOnTouchOutside(false);
progress.show();
}
private void downLoadCs() { //下载调用
initProgressBar();
removeOldApk();
Intent intent = new Intent(this, DownloadServise.class);
intent.putExtra(DownloadServise.BUNDLE_KEY_DOWNLOAD_URL, "http://imtt.dd.qq.com/16891/3804D823FD7A0710F664D0126841BD10.apk?fsname=com.cxtx.chefu.app_1.3.0_39.apk&csr=1bbd");
isBindService = bindService(intent, conn, BIND_AUTO_CREATE); //绑定服务即开始下载 调用onBind()
}
/**
* 删除上次更新存储在本地的apk
*/
private void removeOldApk() {
//获取老APK的存储路径
File fileName = new File(SPTools.getString(Constant.SP_DOWNLOAD_PATH, ""));
if (fileName != null && fileName.exists() && fileName.isFile()) {
fileName.delete();
}
}
最后别忘了在AndroidManifest.xml中声明:
其他参考:
网址1:http://www.jianshu.com/p/bb4cde6e88c6
网址2:http://blog.csdn.net/a907763895/article/details/12753149
Demo1: https://github.com/GitPhoenix/DownloadManager
.