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

在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) {
            @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);
    }

3、更新UI

//转换到主线程
                runOnUiThread(new Runnable() {
                    @Override
                    public 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;

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

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.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;
    }
}

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 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'
}

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

这里用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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值