在github上面苦苦寻找都木有找到有关Android自带下载器DownloadManager多并发下载的,于是就决定自己试试写一个。
先上个图:

我的上篇文章
http://blog.csdn.net/u013277740/article/details/51737080
只实现了单个下载安装,这次升级一下

实现步骤:
1、初始化一个缓存线程池

cachedThreadPool = Executors.newCachedThreadPool();

2、在渲染每一条数据的时候往里面加任务

    private void initView() {mRvList.setLayoutManager(new LinearLayoutManager(this));mDownloadAdapter = new CommonAdapter<Download>(this, R.layout.listitem_mul, mList) {@Overrideprotected void convert(ViewHolder holder, final Download download, int position) {holder.setText(R.id.tv_name, download.getName());//往线程池中增加任务cachedThreadPool.execute(new DownLoadTask(holder, download, position));final NumberProgressBar numberBar = holder.getView(R.id.number_download);holder.setOnClickListener(R.id.btn_install, new View.OnClickListener() {@Overridepublic void onClick(View v) {if (numberBar.getProgress() == 100) {install(MulActivity.this, download.getLastDownLoadId());}}});}};mRvList.setAdapter(mDownloadAdapter);}

3、更新UI

//转换到主线程runOnUiThread(new Runnable() {@Overridepublic void run() {NumberProgressBar numberBar = holder.getView(R.id.number_download);numberBar.setProgress(progress);}});

具体代码如下:

1、MulActivity

package com.zx.download;import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;import com.daimajia.numberprogressbar.NumberProgressBar;
import com.zhy.adapter.recyclerview.CommonAdapter;
import com.zhy.adapter.recyclerview.base.ViewHolder;import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;public class MulActivity extends AppCompatActivity {public static final String DOWNLOAD_ID = "download_id";@Bind(R.id.rv_list)RecyclerView mRvList;private DownloadChangeObserver downloadObserver;public static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");private ExecutorService cachedThreadPool;private List<Download> mList = new ArrayList<>();private CommonAdapter mDownloadAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mul);ButterKnife.bind(this);initData();cachedThreadPool = Executors.newCachedThreadPool();}private void initData() {for (int i = 0; i < Contans.URLS.length; i++) {Download download = new Download();download.setFileName(Contans.FILE_NAMES[i]);download.setName(Contans.NAMES[i]);download.setTitle(Contans.TITLES[i]);download.setDescription(Contans.DESCRIPTIONS[i]);download.setDownLoadUrl(Contans.URLS[i]);mList.add(download);}}private void initView() {mRvList.setLayoutManager(new LinearLayoutManager(this));mDownloadAdapter = new CommonAdapter<Download>(this, R.layout.listitem_mul, mList) {@Overrideprotected void convert(ViewHolder holder, final Download download, int position) {holder.setText(R.id.tv_name, download.getName());cachedThreadPool.execute(new DownLoadTask(holder, download, position));final NumberProgressBar numberBar = holder.getView(R.id.number_download);holder.setOnClickListener(R.id.btn_install, new View.OnClickListener() {@Overridepublic void onClick(View v) {if (numberBar.getProgress() == 100) {install(MulActivity.this, download.getLastDownLoadId());}}});}};mRvList.setAdapter(mDownloadAdapter);}@OnClick(R.id.btn_downs)public void onViewClicked() {initView();}public class DownLoadTask implements Runnable {private ViewHolder holder;private Download downLoad;private int position;public DownLoadTask(ViewHolder holder, Download download, int position) {this.holder = holder;this.downLoad = download;this.position = position;}@Overridepublic void run() {downLoadFile(downLoad);}private void downLoadFile(Download downLoad) {//1.得到下载对象DownloadManager dowanloadmanager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);//2.创建下载请求对象,并且把下载的地址放进去DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downLoad.getDownLoadUrl()));//3.给下载的文件指定路径request.setDestinationInExternalFilesDir(MulActivity.this, Environment.DIRECTORY_DOWNLOADS, downLoad.getFileName());//4.设置显示在文件下载Notification(通知栏)中显示的文字。6.0的手机Description不显示request.setTitle(downLoad.getTitle());request.setDescription(downLoad.getDescription());//5更改服务器返回的minetype为android包类型request.setMimeType("application/vnd.android.package-archive");//6.设置在什么连接状态下执行下载操作request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);//7. 设置为可被媒体扫描器找到request.allowScanningByMediaScanner();//8. 设置为可见和可管理request.setVisibleInDownloadsUi(true);long lastDownloadId = dowanloadmanager.enqueue(request);downLoad.setLastDownLoadId(lastDownloadId);//10.采用内容观察者模式实现进度downloadObserver = new DownloadChangeObserver(null, holder, downLoad, position);getContentResolver().registerContentObserver(CONTENT_URI, true, downloadObserver);}}//用于显示下载进度class DownloadChangeObserver extends ContentObserver {private ViewHolder holder;private Download downLoad;private int position;public DownloadChangeObserver(Handler handler, ViewHolder holder, Download download, int position) {super(handler);this.holder = holder;this.downLoad = download;this.position = position;}@Overridepublic void onChange(boolean selfChange) {DownloadManager.Query query = new DownloadManager.Query();query.setFilterById(downLoad.getLastDownLoadId());DownloadManager dManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);final Cursor cursor = dManager.query(query);if (cursor != null && cursor.moveToFirst()) {final int totalColumn = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);final int currentColumn = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);int totalSize = cursor.getInt(totalColumn);int currentSize = cursor.getInt(currentColumn);float percent = (float) currentSize / (float) totalSize;final int progress = Math.round(percent * 100);runOnUiThread(new Runnable() {@Overridepublic void run() {NumberProgressBar numberBar = holder.getView(R.id.number_download);numberBar.setProgress(progress);}});Log.v("progress" + downLoad.getLastDownLoadId(), progress + "");}}}@Overrideprotected void onDestroy() {super.onDestroy();getContentResolver().unregisterContentObserver(downloadObserver);}//安装private void install(Context context, long downloadId) {Intent install = new Intent(Intent.ACTION_VIEW);File apkFile = queryDownloadedApk(context, downloadId);install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(install);}//通过downLoadId查询下载的apk,解决6.0以后安装的问题public static File queryDownloadedApk(Context context, long downloadId) {File targetApkFile = null;DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);if (downloadId != -1) {DownloadManager.Query query = new DownloadManager.Query();query.setFilterById(downloadId);query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);Cursor cur = downloader.query(query);if (cur != null) {if (cur.moveToFirst()) {String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));if (!TextUtils.isEmpty(uriString)) {targetApkFile = new File(Uri.parse(uriString).getPath());}}cur.close();}}return targetApkFile;}
}

2、activity_mul.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.zx.download.MainActivity"><Button
        android:id="@+id/btn_downs"android:text="开始"android:layout_width="match_parent"android:layout_height="wrap_content" /><android.support.v7.widget.RecyclerView
        android:id="@+id/rv_list"android:layout_width="match_parent"android:layout_height="match_parent"/>
</LinearLayout>

3、Contans

package com.zx.download;/*** Created by user on 2017/6/19.*/public class Contans {private static String NETURL_WEIXIN = "http://gdown.baidu.com/data/wisegame/8d5889f722f640c8/weixin_800.apk";private static String NETURL_QQ = "http://gdown.baidu.com/data/wisegame/41a04ccb443cd61a/QQ_692.apk";private static String NETURL_WANGYIYUN = "http://gdown.baidu.com/data/wisegame/9bfeb688ff2e0a19/wangyiyunyinle_95.apk";private static String NETURL_KUWO = "http://gdown.baidu.com/data/wisegame/82337e10d2a72e61/kuwoyinle_8474.apk";public static final String FILE_NAMES[] = {"weixin1.0.apk", "qq1.0.apk","wyy1.0.apk", "kuwo1.0.apk"};public static final String NAMES[] = {"微信1.0", "QQ1.0","网易云音乐1.0", "酷我音乐1.0"};public static final String URLS[] = {NETURL_WEIXIN, NETURL_QQ, NETURL_WANGYIYUN, NETURL_KUWO};public static final String TITLES[] = {"weixin1.0", "qq1.0","wyy1.0", "kuwo1.0"};public static final String DESCRIPTIONS[] = {"1、新增朋友圈","1、新增QQ空间","1、新增云音乐","1、新增酷我调频"};
}

4、Download

package com.zx.download;import java.io.Serializable;/*** Created by user on 2017/6/19.*/public class Download implements Serializable {private long lastDownLoadId;//weixin.apkprivate String fileName;//weixin1.0private String name;private String downLoadUrl;//通知栏private String title;private String description;public String getDownLoadUrl() {return downLoadUrl;}public void setDownLoadUrl(String downLoadUrl) {this.downLoadUrl = downLoadUrl;}public long getLastDownLoadId() {return lastDownLoadId;}public void setLastDownLoadId(long lastDownLoadId) {this.lastDownLoadId = lastDownLoadId;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}
}

5、UpdataBroadcastReceiver

package com.zx.download;import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;import java.io.File;import cn.trinea.android.common.util.PreferencesUtils;/*** Created by Administrator on 2016/9/20.*/public class UpdataBroadcastReceiver extends BroadcastReceiver {@SuppressLint("NewApi")public void onReceive(Context context, Intent intent) {long downLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);long cacheDownLoadId = PreferencesUtils.getLong(context, MainActivity.DOWNLOAD_ID);if (cacheDownLoadId == downLoadId) {install(context);}}private void install(Context context){Intent install = new Intent(Intent.ACTION_VIEW);File apkFile = queryDownloadedApk(context);install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(install);}//通过downLoadId查询下载的apk,解决6.0以后安装的问题public static File queryDownloadedApk(Context context) {File targetApkFile = null;DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);long downloadId = PreferencesUtils.getLong(context, MainActivity.DOWNLOAD_ID);if (downloadId != -1) {DownloadManager.Query query = new DownloadManager.Query();query.setFilterById(downloadId);query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);Cursor cur = downloader.query(query);if (cur != null) {if (cur.moveToFirst()) {String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));if (!TextUtils.isEmpty(uriString)) {targetApkFile = new File(Uri.parse(uriString).getPath());}}cur.close();}}return targetApkFile;}
}

6、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.zx.download"><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><application
        android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><receiver android:name=".UpdataBroadcastReceiver"><intent-filter><action android:name="android.intent.action.DOWNLOAD_COMPLETE" /></intent-filter></receiver><activity android:name=".MulActivity"></activity></application></manifest>

7、build.gradle

apply plugin: 'com.android.application'android {compileSdkVersion 23buildToolsVersion "23.0.3"defaultConfig {applicationId "com.zx.download"minSdkVersion 14targetSdkVersion 23versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'compile 'com.android.support:appcompat-v7:23.2.1'compile 'com.daimajia.numberprogressbar:library:1.4@aar'compile 'cn.trinea.android.common:trinea-android-common:4.2.15'compile('com.github.afollestad.material-dialogs:core:0.8.5.7@aar') {transitive = true}compile 'com.zhy:base-rvadapter:3.0.3'compile 'com.jakewharton:butterknife:7.0.1'
}

附加一个小功能,怎么判断所有的下载任务都完成了呢?

这里用SparseArray简单实现下

1、实例化一个SparseArray和计数变量

private SparseArray<Integer> progressArray = new SparseArray<>();private int progressCount;

2、在downLoadFile方法中,把每个Key放进去,value都赋值为0

      long lastDownloadId =dowanloadmanager.enqueue(request);downLoad.setLastDownLoadId(lastDownloadId);//把每个key放入map中progressArray.put((int)lastDownloadId, 0);

3、在onChange方法中简单处理

float percent = (float) currentSize / (float) totalSize;
final int progress = Math.round(percent * 100);
runOnUiThread(new Runnable() {@Override
public void run() {
NumberProgressBar numberBar = holder.getView(R.id.number_download);
numberBar.setProgress(progress);
if(progress == 100) {int id = (int)downLoad.getLastDownLoadId();
if(progressArray.get(id) == 0) {
progressArray.put(id, progress);
Log.v("progress === " + downLoad.getLastDownLoadId(), progress + "");
progressCount ++;
if(progressCount == mList.size()) {
Log.v("progress === ","下载完成。。。。。。");
progressCount = 0;}}}}});

最后附上Github源码:
https://github.com/MrXiong/MaterialDownLoad

DownloadManager+NumberProgressBar+Executors线程池实现多并发下载APK安装相关推荐

  1. Executors线程池关闭时间计算

    Executors线程池关闭时间计算 学习了:http://blog.csdn.net/wo541075754/article/details/51564359 https://www.cnblogs ...

  2. Java Executor源码解析(7)—Executors线程池工厂以及四大内置线程池

    详细介绍了Executors线程池工具类的使用,以及四大内置线程池. 系列文章: Java Executor源码解析(1)-Executor执行框架的概述 Java Executor源码解析(2)-T ...

  3. java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...

    线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...

  4. Executors线程池

    //工作中只用这种//最大线程数定义 1.CPU密集型 几核就是几 可保证CPU效率最高Runtime.getRuntime().availableProcessors();//获取CPU核数//IO ...

  5. python线程池模块_python并发编程之进程池,线程池,协程

    需要注意一下 不能无限的开进程,不能无限的开线程 最常用的就是开进程池,开线程池.其中回调函数非常重要 回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去 ...

  6. linux线程池实现多线程并发,基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF...

    基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF 第 卷 第 期 电子设计工程 年 月 基于 的多线程池并发 服务器设计 陈 涛 任海兰 武汉邮电科学研究院 湖北 武汉 摘要 时至今 ...

  7. java多线程抽奖_java 线程池、多线程并发实战(生产者消费者模型 1 vs 10) 附案例源码...

    导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...

  8. 线程池框架_Java并发——Executor框架详解(Executor框架结构与框架成员)

    一.什么是Executor框架? 我们知道线程池就是线程的集合,线程池集中管理线程,以实现线程的重用,降低资源消耗,提高响应速度等.线程用于执行异步任务,单个的线程既是工作单元也是执行机制,从JDK1 ...

  9. java 线程池 -- (Java并发)

    池技术是作为一个架构师必须深刻理解的东西,比如线程池,连接池,对象池,内存池等. 首先需要问一个问题:在c/c++ 编程中,你是如何操作一个任务的或者给一个线程添加任务的?如果你很清楚,那么你知道Ja ...

最新文章

  1. 广东海洋大学数学与计算机学院校友会,数学与计算机学院召开2020级研究生入学教育会...
  2. 李飞飞最新论文:用算法判断政治倾向(附论文链接)
  3. JAVA中throw用法例子,Java Optional orElseThrow()用法及代码示例
  4. python yaml配置文件_python读取yaml配置文件
  5. hsv java_rgb-hsv-hsl-android.java
  6. Django从理论到实战(part7)--关于视图函数与URL映射
  7. ConcurrentHashMap 源码
  8. php 执行exec() 操作linux 命令
  9. Githup高级搜索
  10. 关于scanf对换行的吸收
  11. 智能一代云平台(三十五):后端架构再思考
  12. sublime test3 安装及配置
  13. lol大脚一直卡在读取服务器信息,英雄联盟大脚 - 英雄联盟 - LOL英雄联盟官网 - 英雄联盟攻略 - 英雄联盟专题站...
  14. 计算机c盘无法扩展,win10c盘无法扩展卷怎么办
  15. 新浪微博开放平台开发步骤简介(适合新手看)
  16. 27.(cesium篇)cesium接入百度影像地图
  17. Xenu Link Sleuth
  18. 360无线wifi路由器连接到服务器,两个360路由器如何并连 两个无线路由器桥接设置方法...
  19. 遥感影像 全色 多光谱
  20. javascript实现简单拖曳功能

热门文章

  1. 大数据之spark_spark的Action算子解析
  2. 阿里社招测试开发面经
  3. java二维数组坐标_Java 二维数组
  4. 通过时间戳,计算距离下一个周二和周六的时间距离
  5. java的相对路径和绝对路径_Java 相对路径和绝对路径的区别
  6. myEclipse如何打开与关闭快速导航栏
  7. ios开发--用Xcode 8和Swift 3 构建条形码和二维码识别器
  8. 我的世界服务器java启动脚本_我的世界自动重启脚本教程
  9. Android双卡识别IMSI以及副卡发送短信总结
  10. Linux上快速搭建自己的深度学习虚拟环境