安卓学习笔记6——多线程下载器

  • 一、项目整体介绍
    • 1、项目逻辑流程
    • 2、项目目的:
  • 二、项目代码
  • 三、展示

一、项目整体介绍

使用HttpUrlConnection与服务器建立连接,获取文件长度,开多个线程下载资源,使用RandomAccessFile写入文件;

本项目没有使用高大上的OKhttp

1、项目逻辑流程

2、项目目的:

我把这个小demo写在简历中,有两次面试都问道为什么采用多线程下载,多线程下载比单线程下载的好处?我在这里总结了一下

  1. 多线程主要的优势是与服务器建立多个http链接

多线程下载有可能比单线程下载速度快,多线程主要的优势是与服务器建立多个http链接(目前底层都是tcp,编程就基于socket);相当于多个人搬东西,

  1. 限制下载速度的主要因素是带宽,而不是CPU执行速度

这个带宽指服务器和客户端两端的带宽;若服务器限制每个socket链接传输数据带宽时,多线程下载在服务器端可以获得更大的带宽,若是单个socket服务器端带宽就大于客户端的网络带宽,那么多线程是不会快过单线程的,因为TCP的拥塞控制和流量控制,服务器端发这么块,客户端接收慢,瓶颈就在客户端。

二、项目代码

主活动onCreate方法

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path=(EditText) findViewById(R.id.et_path);et_threadCount =(EditText) findViewById(R.id.et_threadCount);ll_pb_layout=(LinearLayout) findViewById(R.id.ll_layout);pbList=new ArrayList<ProgressBar>();//        获取权限String[] PERMISSIONS_STORAGE = {Manifest.permission.INTERNET,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,};for (String str : PERMISSIONS_STORAGE){int permission = ActivityCompat.checkSelfPermission(MainActivity.this, str);if(permission!= PackageManager.PERMISSION_GRANTED) {// We don't have permission so prompt the userActivityCompat.requestPermissions(MainActivity.this,PERMISSIONS_STORAGE,1);}}}

下载资源线程

 private class DownLoadThread extends Thread {//通过构造方法把每个线程下载的开始位置和结束位置传递进来private int startIndex;private int endIndex;private int threadId;private int PbMaxSize;//代表当前线程下载的最大值
//       如果中断过获取上次下载的位置private int pblastPostion;public DownLoadThread(int startIndex, int endIndex, int threadId) {this.startIndex = startIndex;this.endIndex = endIndex;this.threadId = threadId;}@Overridepublic void run() {try{//计算当前进度条的最大值PbMaxSize=endIndex-startIndex;URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);//[4.0]如果中间断过继续上次的位置继续下载从文件中读取上次下载的位置File file=new File(getFilename(path)+threadId+".txt");if(file.exists() && file.length()>0){FileInputStream fis=new FileInputStream(file);BufferedReader bufr=new BufferedReader(new InputStreamReader(fis));String lastPositionn =bufr.readLine();int lastPosition=Integer.parseInt(lastPositionn);pblastPostion=lastPosition-startIndex;startIndex=lastPosition+1;System.out.println("线程id"+threadId+"真实下载的位置:"+startIndex+"---"+endIndex);fis.close();}conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);int code =conn.getResponseCode();if(code==206){RandomAccessFile raf=new RandomAccessFile(getFilename(path),"rw");raf.seek(startIndex);InputStream in=conn.getInputStream();int len=-1;byte[] buffer =new byte[1024*1024];int total=0;while((len=in.read(buffer))!=-1){raf.write(buffer,0,len);total+=len;
//实现断点续传就是把当前线程下载的位置给存起来下次再下载的时候就是按照上次下载的位置继续下载就可以了int currentThreadPosition =startIndex+total;RandomAccessFile raff=new RandomAccessFile(getFilename(path)+threadId+".txt","rwd");raff.write(String.valueOf(currentThreadPosition).getBytes());raff.close();
//[10]设置一下当前进度条的最大值和当前进度,无需在子线程中更新pbList.get(threadId).setMax(PbMaxSize);pbList.get(threadId).setProgress(pblastPostion+total);}raf.close();System.out.println("线程id:"+threadId+"---下载完毕了");//synchronized (DownLoadThread.class){runningThread--;if(runningThread==0){for (int i=0;i<threadCount;i++){File delteFile =new File(getFilename(path)+i+".txt");delteFile.delete();}}}}}catch(Exception e){e.printStackTrace();}}}

其他

    //获取文件的名字"http://192.168.11.73:8080/feiq.exe"public String getFilename(String path) {int start = path.lastIndexOf("/") + 1;String substring =path.substring(start);String filename = Environment.getExternalStorageDirectory().getPath()+"/"+substring;return filename;}

按钮点击事件

public void click(View v){//[2]获取下载的路径path=et_path.getText().toString().trim();//[3]获取线程的数量String threadCountt =et_threadCount.getText().toString().trim();threadCount=Integer.parseInt(threadCountt);
//先移除进度条在添加ll_pb_layout.removeAllViews();pbList.clear();for(int i=0;i< threadCount;i++) {//[3.1]把我定义的item布局转换成一个view对象ProgressBar pbview = (ProgressBar) View.inflate(getApplicationContext(), R.layout.item, null);pbList.add(pbview);//[4]动态的添加进度条ll_pb_layout.addView(pbview);}
//        创建子线程去获取文件大小,
//        获取到大小后,根据线程下载数,再循环开多个线程去取部分资源new Thread(){@Overridepublic void run() {try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);int code = conn.getResponseCode();if (code == 200)//200代表获取服务器资源全部成功206请求部分资源{//(6)获取服务器文件的大小int length = conn.getContentLength();runningThread = threadCount;System.out.println("length:" + length);RandomAccessFile randomAccessFile = new RandomAccessFile(getFilename(path), "rw");randomAccessFile.setLength(length);//(7)算出每个线程下载的大小|int blockSize = length / threadCount;for (int i = 0; i < threadCount; i++) {int startIndex = i * blockSize;//每个线//特殊情况就是最后一个线程int endIndex = (i + 1) * blockSize - 1;if (i == threadCount - 1) {//说明是最后一个线程endIndex = length - 1;}System.out.println("线程id:" + i + "理论下载的位置:" + startIndex + "-----" + endIndex);DownLoadThread thread=new DownLoadThread(startIndex,endIndex,i);thread.start();}}}catch(Exception e){e. printStackTrace();}}}.start();}

三、展示

我的本地带宽是50M
单个线程


多个线程

安卓学习笔记6——多线程下载器相关推荐

  1. 安卓day29网络编程 HttpClient AsyncHttpClient 断点续传多线程下载器 HttpUtils

    一.排坑 HttpClient.Header飘红 Android 6.0 已经移除了httpClient module下的build.gradle中加入: android{useLibrary 'or ...

  2. 2020年安卓学习笔记目录

    文章目录 一.讲课笔记 二.安卓案例 三.安卓实训项目 四.学生安卓学习博客 五.安卓课后作业 (一)界面设计练习 1.制作登录界面 2.制作部队管理界面 3.制作灭火救援界面 4.制作交付界面 5. ...

  3. android没有adm_这可能是安卓平台上最好的下载器:ADM

    下载一直是安卓用户难以磨灭的痛苦,PC上的P2P神器迅雷在安卓平台上的表现也是差强人意.其实除了P2P下载之外,多线程下载也是一种不错的解决方案.他既没有P2P对于上传的要求,也不会占用过多的CPU功 ...

  4. Golang多线程下载器(附代码、可执行文件)

    个人学习记录,欢迎提出不足之处~ 文章目录 1. 功能介绍(使用方法) 2. 完整代码(带少量注释) 3. 可执行文件(exe) 4. 下载器实现思想(待续) 5. 代码详细解析(待续) 1. 功能介 ...

  5. JAVA多线程下载器

    大二末了,选好了方向,而去也喜欢网络并发,多线程之类的,就决定做个多线程下载器,学习学习文件,网络,线程间通讯的方法. 代码其实早就开始写,只是一直比较忙,也没写多少.今天认真花了一天把下载线程写了. ...

  6. 安卓学习笔记之骚扰拦截

    安卓学习笔记之骚扰拦截 1.监听电话状态 2.检测来电号码是否匹配拦截条件 3.若匹配,则挂断电话 实例代码: 获取TelephonyManager 对象,并监听来电状态 TelephonyManag ...

  7. Python:教你如何实现多线程下载器

    hello,大家好,我是wangzirui32,今天我们来学习如何使用Python实现多线程下载器,开始学习吧! 1. 流程&原理 将HEAD请求发送到目标URL,获取文件的大小 根据文件大小 ...

  8. 手把手教你实现一个 Python 多线程下载器

    前言 下载文件是我们生活中的一个常见的需求,因此衍生的下载工具也非常多,各有各的优势以及不足之处.作为一个编程爱好者,我喜欢去研究它们是怎么实现文件下载功能的. 我的主要使用的编程语言是 Python ...

  9. JVM学习笔记-03-类加载器及双亲委派机制

    JVM学习笔记-03-类加载器及双亲委派机制 文章目录 JVM学习笔记-03-类加载器及双亲委派机制 1. 类加载器 视频链接-最新JVM教程IDEA版[Java面试速补篇]-03-类加载器及双亲委派 ...

  10. Python 学习笔记9(装饰器,decorator)

    Python 学习笔记9(装饰器,decorator) 31 装饰器 装饰器可以对一个函数.方法或者类进行加工,是一种高级的python语法. 装饰函数 接收一个可调用对象作为输入参数,并返回一个新的 ...

最新文章

  1. R语言使用table1包绘制(生成)三线表、使用单变量分列构建三线表、设置transpose参数转置三线表、变量作为列,子组(strata)作为行
  2. 以太网帧,ARP报文
  3. 抖音小程序微信小程序五角星型评分插件自定义分数组件
  4. 谋定重整衍生新360行-李玉庭:协同电商经信研究生态系统
  5. CNN结构:用于检测的CNN结构进化-分离式方法
  6. azure blob_使用Azure Blob存储托管Maven工件
  7. Python动态创建变量的方法
  8. 上海医疗救治专家组组长:没有讨价还价!
  9. Typora自动生成标题编号(包含从二级标题开始的)
  10. 离散元pfc、3dec 专题
  11. 【ONE·Linux || 权限 】
  12. 射频识别技术在手机支付技术中的应用
  13. 线程控制-客户端获取信息无反应
  14. 《人月神话》——The Mythical Man-Month 读书笔记
  15. 教育系统APP(一)
  16. X230网卡驱动安装总不成功的问题
  17. steam搬砖价值3000的教程
  18. vim:精通 vim
  19. 多晴转云h_上海2021年1月13日天气:晴,气温:4~14℃
  20. Openfiler的安装+ISCSI和NFS共享存储的基础配置

热门文章

  1. idea 离线安装sonarlint 插件
  2. fastboot工具使用
  3. ISO50001认证辅导,ISO50001验厂优化所有流程中的能源性能,促进更高效的能源管理
  4. 信号与线性系统分析(吴大正,郭宝龙)(2-冲激函数)
  5. 《软件工程》网上书店项目需求规格说明书
  6. 益智棋类游戏--走四棋儿
  7. 常见驱动程序相关知识
  8. 前端面试宝典总结(一)(搬自牛客)
  9. 如何在 Linux 中运行.exe 程序
  10. 电流纹波率取r = 0.4的原因 // 《精通开关电源设计》P48:r的最优值