android多线程下载

文章的开头奉送上代码,已方便大家对照学习。(因为电脑卡的原因,代码是用eclipse编写,给大家带来不便还请见谅。)

1 前言

1.1多线程下载

APP更新的时候如果单线程下载的话相对来说是比较慢的。但是如果能把APK分成几段,分别用线程下载的话,就会快很多。接下来就来讲解一下多线程下载。

1.2断点续传

多线程下载如果理解了,断点续传就好做多了。用数据库保存相关断点,继续下载就行,这里就不介绍了。

2 实现思路

2.1 用到的核心知识点

1.RandomAccessFile 随机访问文件的读写。
2.BufferedInputStream缓冲流的读写。
3.URLConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);设置下载的起至段。

2.2 实现思路

1.启动服务service,在服务中启动线程请求地址,获取下载内容大小。
2.根据下载内容的大小分成3段,分成3个线程分别下载。
3.在每个线程中分成设置下载位置进行分别下载。
4.将下载下来的流利用RandomAccessFile写入文件。

总体的实现思路就是这样的。下面来讲一下编码实现。

3 代码实现

3.1 启动服务

Intent intent = new Intent("com.action.downloadservice");
startService(intent);

3.2 DownLoadService类的代码

/**
 * @author 作者 YYD
 * @version 创建时间:2016年12月28日 下午1:59:07
 * @function 未添加
 */
@SuppressLint("NewApi")
public class DownLoadService extends Service implements Callback {
    private Handler handler = new Handler(this);
    private int allFileLength = 0;//软件总大小
    private int currentFileLenght = 0;//当前下载的数量
    private long preDownLoadTime = 0;//下载前的时间记录
    private int ThreadNum = 3;//线程数
    @Override
    public void onCreate() {
        super.onCreate();
        preDownLoadTime = System.currentTimeMillis();
        mulitDownload();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    /**
    *这个是handler用于计算3个线程下在的总进度,
    *如果(下载的大小==总内容长度)说明下载完了。
    */
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
        case 1000:
            int num = msg.arg1;
            currentFileLenght += num;
            if(currentFileLenght == allFileLength){
                Log.d("refreshlistview", "下载完毕!"+"消耗时间:"+((System.currentTimeMillis() - preDownLoadTime)/1000));
            }
            break;
        }
        return false;
    }

    /**
     * 多线程下载
     * 这个是核心代码,思路如下:
     * 1.线程请求网络,获取内容长度。
     * 2.根据下载内容长度,分3段,分3个线程分别下载。
     * 比如:现在长度是1534。
     *      第一段是:0 ~ 1500/3*1 - 1
     *      第二段是:1500/3*1 ~ 1500/3*2 - 1
     *      第三段是:1500/3*2 ~ 1534
     * 这就是for循环中的逻辑,用for循环分别启动3个线程来下载这3段。
     */
    private void mulitDownload() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(UrlManager.url);
                    URLConnection connection = url.openConnection();
                    allFileLength = connection.getContentLength();// 获取内容的长度
                    File file = new File(
                            Environment.getExternalStorageDirectory(),
                            "gaoyipin.apk");
                    if (!file.exists()) {
                        boolean isCreate = file.createNewFile();
                    }
                    DownLoadThread[] threads = new DownLoadThread[ThreadNum];// 用于管理下载线程
                    for (int i = 0; i < ThreadNum; i++) {
                        DownLoadThread thread = null;
                        if (i == (ThreadNum -1)) {
                            thread = new DownLoadThread(allFileLength / ThreadNum * (ThreadNum-1), allFileLength,
                                    file, handler, i);
                        } else {
                            thread = new DownLoadThread(allFileLength / ThreadNum * i, allFileLength
                                    / ThreadNum * (i + 1) - 1, file, handler, i);
                        }
                        thread.start();
                        threads[i] = thread;
                    }

                } catch (Exception e) {
                    Log.d("refreshlistview", "下载前异常");
                }
            }
        }).start();
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("refreshlistview", "服务停止");
    }
}

3.3 DownLoadThread类的代码

/**
 * @author 作者 YYD
 * @version 创建时间:2016年12月28日 下午2:06:00
 * @function 未添加
 */
public class DownLoadThread extends Thread {
    private int process = 0;
    private int startPos = 0;//开始下载位置
    private int endPos = 0;//结尾下载的进度
    private File downLoadFile;//要下载的文件
    private Handler handler ;
    public DownLoadThread(int startPos, int endPos, File downLoadFile,Handler handler,int threadId) {
        super(""+threadId);
        this.startPos = startPos;
        this.endPos = endPos;
        this.downLoadFile = downLoadFile;
        this.handler = handler;
        Log.d("refreshlistview", "startPos:"+startPos+"  endPos: "+endPos);     
    }

    @Override
    public void run() {
        super.run();
        try {
            URL url = new URL(UrlManager.url);
            URLConnection connection = url.openConnection();
            connection.setAllowUserInteraction(true);
            connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
            InputStream is = connection.getInputStream();
            RandomAccessFile raf = new RandomAccessFile(
                    downLoadFile.getAbsolutePath(), "rw");// 随机访问文件的读写,第一个参数是文件的路径
            raf.seek(startPos);
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buffer = new byte[2048];
            int writeNum = -1;
            while ((writeNum = bis.read(buffer))> 0) {
                raf.write(buffer,0,writeNum);

                Message msg = new Message();
                msg.what = 1000;
                msg.arg1 = writeNum;
                handler.sendMessage(msg);
                process += writeNum;

            }
            Log.d("refreshlistview", "线程"+getName()+"下载完毕");    
            raf.close();
            bis.close();
            is.close();
        } catch (Exception e) {
            Log.d("refreshlistview", "线程"+getName()+"下载异常:"+e.toString());          
        }
    }
}

4 结尾

文章的最后奉送上代码,方便大家对照学习。

好了就讲到这里吧,在技术上我依旧是个小渣渣,加油,勉励自己!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序编织梦想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值