android 线程下载之(断点续传)

简言:

android 下载在开发中是非常常见的,下载一个视频,下载一个图片等等,我们本篇博客主要讲解 的是如何断点续传实现下载图片,apk等,开始躁动起来       

1.什么是线程

线程主要分为主线程:主要处理界面相关的事情,

                      子线程: 处理一些耗时操作

2.都有哪些线程?

线程除了Thread之外,还有asyncTask,InterService,handlerThread,

我们常见的就是AsyncTask,它主要做一些耗时的操作,耗时操作完成后更新主线程UI;

存在缺陷就是AsyncTask维护一个长度为128的线程池,当我们缓存队列满的时候,我们向线程提交任务的时候回抛出异常,

3.AsyncTask

它是一个抽象的泛型参数,有三个泛型参数:

1)params: 表示输入的参数类型

2)progress: 表示后台执行任务的进度类型

3)result: 后台任务返回结果

AsyncTask还有四个核心方法

1)onPreExecture: 在执行异步之前执行,做一些准备工作

2)doInBackground: 执行异步任务的,通过publshProgress跟新任务进度

3)onProgressUpdate: 在后台执行任务发生改变是调用

4)onPostexecture: 在后台异步任务执行之后调用,将结果返回

4.实现断点续传下载图片

线程已经了解了 ,我们实现断点续传(

1)首先自定义一个线程ThreadManger来集成Thread(直接上代码)

private int threadId; // 线程ID
private int startPosition; // 下载开始位置
private int endPosition; // 下载结束位置
private String fileName; // 文件名称
private String urlPath; // 文件路径
private DownloadManager.Progress progress;
private int all;

public ThreadManger(int threadId, int startPosition, int endPosition, String fileName, String urlPath, DownloadManager.Progress progress, int all) {
    this.threadId = threadId;
    this.startPosition = startPosition;
    this.endPosition = endPosition;
    this.fileName = fileName;
    this.urlPath = urlPath;
    this.progress = progress;
    this.all = all;
}

@Override
public void run() {
    super.run();
    HttpURLConnection conn = null;
    InputStream is = null;
    RandomAccessFile accessFile = null;
    try {
        URL url = new URL(urlPath);
        conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(3000);// 超时时间
        conn.setRequestMethod("GET"); //get请求
        conn.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);//断点下载的位置
        conn.connect();
        int code = conn.getResponseCode(); // 获取返回值,应该为206 200是不能断点下载的
        System.out.println("线程ID" + threadId);
        System.out.println("返回码" + code);
        is = conn.getInputStream(); //获取输入流
        byte[] buff = new byte[1024]; // 设置缓存
        int len;
        accessFile = new RandomAccessFile(fileName,"rwd");
        accessFile.seek(startPosition);
        while ((len= is.read(buff))!= -1){
            accessFile.write(buff,0,len);
            progress.get(len,all);// 调用接口来获取进度
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        try {
            if(conn != null){
                conn.disconnect();
            }
            if(is != null){
                is.close();
            }
            if(accessFile != null){
                accessFile.close();
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

2)接下在我们创建一个下载管理类DownloadManager:

1.首先创建一个接口实现回调下载进度

public interface Progress {
    void get(int size, int all);
}

2. 然后进行断点续传下载

public void downLoadFileTest() {
    HttpURLConnection conn = null;
    String fileName = null;
    InputStream inputStream = null;
    RandomAccessFile accessFile = null;
    try {
        URL url = new URL(urlPath);
        conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        conn.connect();
        int code = conn.getResponseCode();
        int size = conn.getContentLength();
        Map<String, List<String>> map = conn.getHeaderFields();
        for (String str : map.keySet()) {
            if (str != null) {
                System.out.println("H3c : " + str + map.get(str));
            }
        }
        fileName = conn.getHeaderField("Content-Disposition");
        if (fileName == null || fileName.length() < 1) {
            fileName = url.getFile();
            fileName = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length());
        } else {
            fileName = fileName.substring(fileName.indexOf("=") + 1, fileName.length());
            if (fileName.indexOf("\"") == 0) {
                fileName = fileName.replaceAll("\"", " ").trim();
            }
        }
        System.out.println("文件名字:" + fileName);
        File file = new File(Environment.getExternalStorageDirectory(), fileName);
        int every = size % 4 == 0 ? (size / 4) : (size / 4 + 1);
        accessFile = new RandomAccessFile(file, "rwd");
        accessFile.setLength(size);
        accessFile.close();
        for (int i = 0; i < 4; i++) {
            new ThreadManger(i, i * every, (i + 1) * every - 1,
                    file.getAbsolutePath(), urlPath,
                    progress == null ? progress = null : progress, size).start();
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {

        try {
            if (conn != null) {
                conn.disconnect();
            }
            if (inputStream != null) {
                inputStream.close();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3)实现下载 (在你需要下载的activity中或者service中 *注意权限的添加)

if(requestCode == 1000){
     if(isDownLoad){
         Toast.makeText(this,"文件正被下载中!",Toast.LENGTH_SHORT).show();
         return;
     }
     isDownLoad = true;
     count =0;//初始计数器
     // 获取下载器
     final DownloadManager manager = new DownloadManager("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1561526007730&di=925b6a30de0b17a3a4154dc30584b86d&imgtype=0&src=http%3A%2F%2Fgss0.baidu.com%2F-vo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2F14ce36d3d539b60037ca72abef50352ac65cb7a1.jpg");
     //开启子线程
     new Thread(){
         @Override
         public void run() {
             super.run();
             manager.downLoadFileTest();
             handler.sendEmptyMessage(100);
         }
     }.start();

     //获取下载进度
     manager.setProgessLisener(new DownloadManager.Progress() {
         //初始化sum
         float sum = 0;
         @Override
         public void get(int size, int all) {
             sum += size;
             //获取最接近的整数
             int progress = Math.round(sum/(float) all*100);
             if(progress == 100){
                 count += 1;
                 handler.sendEmptyMessage(300);
             }
             if(count <=1){
                 //更新进度
                 handler.obtainMessage(200,progress).sendToTarget();
             }
         }
     });
 }

5.通过Handler实现下载状态的更新(在你需要下载的activity中或者service中 *注意权限的添加)

private Handler handler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
      switch (msg.what){
          case 100:
              bar.setVisibility(View.VISIBLE);
              image.setVisibility(View.VISIBLE);
              break;
          case 200:
              int progress = (int)msg.obj;
              if(progress == 100){
                  Toast.makeText(MainActivity.this, "下载完成!", Toast.LENGTH_SHORT).show();
              }
              bar.setProgress(progress);
              break;
          case 300:
              isDownLoad = false;
              Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
              break;



      }
        return false;
    }
});

整个断线续传就完事了,

6)针对handler做一个简单的了解:

在线程内部有一个或者多个handler对象,通过该handler对象向线程发送异步消息,消息经过handler传递到消息队列中(messageQueue),线程内部只能包含一个消息队列,然后消息队列中经读取数据,并回调Handler对象中的回调参数handlerMessage

项目地址:

链接:https://pan.baidu.com/s/1wsC1-AUxO6gWCN8rL8G7cg
提取码:6w6g  
 

如果对你有所帮助,帮忙点一个赞。

发布了96 篇原创文章 · 获赞 370 · 访问量 42万+

猜你喜欢

转载自blog.csdn.net/wk_beicai/article/details/93735059