简言:
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> 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
如果对你有所帮助,帮忙点一个赞。