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

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


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

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

cachedThreadPool = Executors.newCachedThreadPool();
1
2、在渲染每一条数据的时候往里面加任务

    private void initView() {
        mRvList.setLayoutManager(new LinearLayoutManager(this));
        mDownloadAdapter = new CommonAdapter<Download>(this, R.layout.listitem_mul, mList) {
            @Override
            protected 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() {
                    @Override
                    public void onClick(View v) {
                        if (numberBar.getProgress() == 100) {
                            install(MulActivity.this, download.getLastDownLoadId());
                        }
                    }
                });
            }
        };
        mRvList.setAdapter(mDownloadAdapter);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
3、更新UI

//转换到主线程
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        NumberProgressBar numberBar = holder.getView(R.id.number_download);
                        numberBar.setProgress(progress);
                    }
                });
1
2
3
4
5
6
7
8
具体代码如下:

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;

    @Override
    protected 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) {
            @Override
            protected 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() {
                    @Override
                    public 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;

        }

        @Override
        public 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;
        }

        @Override
        public 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() {
                    @Override
                    public void run() {
                        NumberProgressBar numberBar = holder.getView(R.id.number_download);
                        numberBar.setProgress(progress);
                    }
                });

                Log.v("progress" + downLoad.getLastDownLoadId(), progress + "");
            }
        }


    }

    @Override
    protected 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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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、新增酷我调频"};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.apk
    private String fileName;
    //weixin1.0
    private 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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
7、build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    defaultConfig {
        applicationId "com.zx.download"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles 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'
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
附加一个小功能,怎么判断所有的下载任务都完成了呢?

这里用SparseArray简单实现下

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

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

private int progressCount;
1
2
3
2、在downLoadFile方法中,把每个Key放进去,value都赋值为0

      long lastDownloadId =dowanloadmanager.enqueue(request);
            downLoad.setLastDownLoadId(lastDownloadId);

            //把每个key放入map中
            progressArray.put((int)lastDownloadId, 0);
1
2
3
4
5
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;
                                }

                            }
                        }

                    }
                });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
最后附上Github源码:
https://github.com/MrXiong/MaterialDownLoad
————————————————
版权声明:本文为CSDN博主「大雄童鞋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013277740/article/details/73467980

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值