• android 多线程下载 断点续传


    来源:网易云课堂Android极客班第八次作业练习

    练习内容: 多线程 asyncTask handler

    多线程下载的原理

    首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把目标文件分割成n份,分别创建线程下载.

    获取目标文件的大小

                        //使用目标文件的下载链接作为发起网络请求
                        mUrl = new URL("http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk");
                        //注意不是URLConnection, URLConnection是抽象类,HttpURLConnection是它的子类
                        HttpURLConnection urlConnection = (HttpURLConnection) mUrl.openConnection();
                        urlConnection.setRequestMethod("GET");
                        urlConnection.setConnectTimeout(5000);
                        
                        //获取目标文件的大小
                        mContentLength = urlConnection.getContentLength();
    

    在磁盘上申请一块空间,用于保存目标文件,这里用到了RandomAccessFile类,该类的seek()方法能够非常方便的对文件进行指定位置的定位.

                        mFile = new File(Environment.getExternalStorageDirectory(), getFileName(params[0]));
                        if (mFile.exists()) {//如果文件已经存在,删除
                            mFile.delete();
                        }
                        RandomAccessFile randomFile = new RandomAccessFile(mFile, "rw");
                        //设置文件大小
                        randomFile.setLength(mContentLength);
    

    分割文件,分别创建线程进行下载(只需要关注非注释内容)

                        int blockSize = mContentLength / 3;
                        for (int i = 0; i < 3; i++) {
                            int begin = i * blockSize;
                            int end = (i + 1) * blockSize - 1;
                            if (i == 2) {
                                end = mContentLength;
                            }
                            //HashMap<String, Integer> map = new HashMap<>();
                            //map.put("begin", begin);
                            //map.put("end", end);
                            //map.put("finished", 0);
                            //threadList.add(map);
                            
                            //new Thread
                            new Thread(new DownloadThread(i, begin, end, mFile, mUrl)).start();
                        }
    
    

    断点续传的原理

    在每个线程进行下载的过程中,每次写入文件的时候,记录已经下载了多少内容,重新开始下载时,从上次结束的位置继续下载.

    数据结构

    使用HashMap存储该线程下载文件的起始位置,结束位置和已完成大小,并使用一个ArrayList存储各线程数据

        private List<HashMap<String, Integer>> threadList = new ArrayList<>();
    
                            HashMap<String, Integer> map = new HashMap<>();
                            map.put("begin", begin);//开始位置
                            map.put("end", end);//结束位置
                            map.put("finished", 0);//已完成
    

    发起网络请求时,指定起止位置

                    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                    urlConnection.setRequestMethod("GET");
    
                    //指定起止位置
                    urlConnection.setRequestProperty("Range", "bytes=" + begin + "-" + end);
    

    下载时更新map中的finished字段的值

                    while ((len = is.read(buf)) != -1 && isDownloading) {
                        randomFile.write(buf, 0, len);
                        updateProgress(len);
    
                        //更新map中的finished字段的值
                        map.put("finished", map.get("finished") + len);
                    }
    

    再次开始下载时,更新每个线程的开始位置(即实例化DownloadThread类时所需要的第二个参数)

                    for (int i = 0; i < threadList.size(); i++) {
                        HashMap<String, Integer> map = threadList.get(i);
                        new Thread(new DownloadThread(i, map.get("begin") + map.get("finished"), map.get("end"), mFile, mUrl)).start();
                    }
    

    更新ui的操作

    自定义handler

                public static class DownloadHandler extends android.os.Handler {
                    public final WeakReference<MainActivity> mActivity;
            
                    public DownloadHandler(MainActivity activity) {
                        mActivity = new WeakReference<MainActivity>(activity);
                    }
            
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        MainActivity activity = mActivity.get();
            
                        switch (msg.what) {
                            case 0:
                                int progress = (int) msg.obj;
                                activity.getProgressBar().setProgress(progress);
                                if (progress == 100) {
            //                        Toast.makeText(activity, "下载成功",Toast.LENGTH_SHORT).show();
                                    activity.getDownloadButton().setText("下载成功");
                                }
                        }
                    }
                }
          
    

    更新UI的方法

                //使用synchronized
                synchronized private void updateProgress(int len) {
                    total += len;
                    int temp = total * 100 / mContentLength;
                    mDownloadHandler.obtainMessage(0, temp).sendToTarget();
                }
    

    完整代码github地址:https://github.com/zhangbz/MultithreadingDownloadDemo

  • 相关阅读:
    php面试专题---16、MySQL创建高性能索引考点
    php面试专题---Mysql索引类型、介绍及优点
    php面试专题---Mysql索引原理及SQL优化
    北风设计模式课程---责任链模式 总结
    黑马lavarel教程---2、获取用户输入
    php面试专题---15、MySQL数据库基础考察点
    北风设计模式课程---外观模式、代理模式和中介者模式的区别
    legend3---1、meedu安装
    mysql中utf8和utf8mb4区别
    Struts2基于注解的Action配置
  • 原文地址:https://www.cnblogs.com/happyhacking/p/5290863.html
Copyright © 2020-2023  润新知