Android之多线程断点下载

本文主要包含多线程下载的一些简单demo,包括三部分

  1. java实现
  2. android实现
  3. XUtils开源库实现

注意下载添加网络权限与SD卡读写权限

java实现多线程下载

public class MutileThreadDownload {/*** 线程的数量*/private static int threadCount = 3;/*** 每个下载区块的大小*/private static long blocksize;/*** 正在运行的线程的数量*/private static int runningThreadCount;/*** @param args* @throws Exception*/public static void main(String[] args) throws Exception {// 服务器文件的路径String path = "http://192.168.1.100:8080/ff.exe";URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);int code = conn.getResponseCode();if (code == 200) {long size = conn.getContentLength();// 得到服务端返回的文件的大小System.out.println("服务器文件的大小:" + size);blocksize = size / threadCount;// 1.首先在本地创建一个大小跟服务器一模一样的空白文件。File file = new File("temp.exe");RandomAccessFile raf = new RandomAccessFile(file, "rw");raf.setLength(size);// 2.开启若干个子线程分别去下载对应的资源。runningThreadCount = threadCount;for (int i = 1; i <= threadCount; i++) {long startIndex = (i - 1) * blocksize;long endIndex = i * blocksize - 1;if (i == threadCount) {// 最后一个线程endIndex = size - 1;}System.out.println("开启线程:" + i + "下载的位置:" + startIndex + "~"+ endIndex);new DownloadThread(path, i, startIndex, endIndex).start();}}conn.disconnect();}private static class DownloadThread extends Thread {private int threadId;private long startIndex;private long endIndex;private String path;public DownloadThread(String path, int threadId, long startIndex,long endIndex) {this.path = path;this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;}@Overridepublic void run() {try {// 当前线程下载的总大小int total = 0;File positionFile = new File(threadId + ".txt");URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");// 接着从上一次的位置继续下载数据if (positionFile.exists() && positionFile.length() > 0) {// 判断是否有记录FileInputStream fis = new FileInputStream(positionFile);BufferedReader br = new BufferedReader(new InputStreamReader(fis));// 获取当前线程上次下载的总大小是多少String lasttotalstr = br.readLine();int lastTotal = Integer.valueOf(lasttotalstr);System.out.println("上次线程" + threadId + "下载的总大小:"+ lastTotal);startIndex += lastTotal;total += lastTotal;// 加上上次下载的总大小。fis.close();}conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);conn.setConnectTimeout(5000);int code = conn.getResponseCode();System.out.println("code=" + code);InputStream is = conn.getInputStream();File file = new File("temp.exe");RandomAccessFile raf = new RandomAccessFile(file, "rw");// 指定文件开始写的位置。raf.seek(startIndex);System.out.println("第" + threadId + "个线程:写文件的开始位置:"+ String.valueOf(startIndex));int len = 0;byte[] buffer = new byte[512];while ((len = is.read(buffer)) != -1) {RandomAccessFile rf = new RandomAccessFile(positionFile,"rwd");raf.write(buffer, 0, len);total += len;rf.write(String.valueOf(total).getBytes());rf.close();}is.close();raf.close();} catch (Exception e) {e.printStackTrace();} finally {// 只有所有的线程都下载完毕后 才可以删除记录文件。synchronized (MutileThreadDownload.class) {System.out.println("线程" + threadId + "下载完毕了");runningThreadCount--;if (runningThreadCount < 1) {System.out.println("所有的线程都工作完毕了。删除临时记录的文件");for (int i = 1; i <= threadCount; i++) {File f = new File(i + ".txt");System.out.println(f.delete());}}}}}}
}

安卓实现

public class MainActivity extends Activity {protected static final int DOWNLOAD_ERROR = 1;private static final int THREAD_ERROR = 2;public static final int DWONLOAD_FINISH = 3;private EditText et_path;private EditText et_count;/*** 存放进度条的布局*/private LinearLayout ll_container;/*** 进度条的集合*/private List<ProgressBar> pbs;/*** android下的消息处理器,在主线程创建,才可以更新ui*/private Handler handler = new Handler(){public void handleMessage(Message msg) {switch (msg.what) {case DOWNLOAD_ERROR:Toast.makeText(getApplicationContext(), "下载失败", 0).show();break;case THREAD_ERROR:Toast.makeText(getApplicationContext(), "下载失败,请重试", 0).show();break;case DWONLOAD_FINISH:Toast.makeText(getApplicationContext(), "下载完成", 0).show();break;}};};/*** 线程的数量*/private int threadCount = 3;/*** 每个下载区块的大小*/private long blocksize;/*** 正在运行的线程的数量*/private  int runningThreadCount;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);et_count = (EditText) findViewById(R.id.et_count);ll_container = (LinearLayout) findViewById(R.id.ll_container);}/*** 下载按钮的点击事件* @param view*/public void downLoad(View view){//下载文件的路径final String path = et_path.getText().toString().trim();if(TextUtils.isEmpty(path)){Toast.makeText(this, "对不起下载路径不能为空", 0).show();return;}String count = et_count.getText().toString().trim();if(TextUtils.isEmpty(path)){Toast.makeText(this, "对不起,线程数量不能为空", 0).show();return;}threadCount = Integer.parseInt(count);//清空掉旧的进度条ll_container.removeAllViews();//在界面里面添加count个进度条pbs = new ArrayList<ProgressBar>();for(int j=0;j<threadCount;j++){ProgressBar pb = (ProgressBar) View.inflate(this, R.layout.pb, null);ll_container.addView(pb);pbs.add(pb);}Toast.makeText(this, "开始下载", 0).show();new Thread(){public 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) {long size = conn.getContentLength();// 得到服务端返回的文件的大小System.out.println("服务器文件的大小:" + size);blocksize = size / threadCount;// 1.首先在本地创建一个大小跟服务器一模一样的空白文件。File file = new File(Environment.getExternalStorageDirectory(),getFileName(path));RandomAccessFile raf = new RandomAccessFile(file, "rw");raf.setLength(size);// 2.开启若干个子线程分别去下载对应的资源。runningThreadCount = threadCount;for (int i = 1; i <= threadCount; i++) {long startIndex = (i - 1) * blocksize;long endIndex = i * blocksize - 1;if (i == threadCount) {// 最后一个线程endIndex = size - 1;}System.out.println("开启线程:" + i + "下载的位置:" + startIndex + "~"+ endIndex);int threadSize = (int) (endIndex - startIndex);pbs.get(i-1).setMax(threadSize);new DownloadThread(path, i, startIndex, endIndex).start();}}conn.disconnect();} catch (Exception e) {e.printStackTrace();Message msg = Message.obtain();msg.what = DOWNLOAD_ERROR;handler.sendMessage(msg);}};}.start();}private class DownloadThread extends Thread {private int threadId;private long startIndex;private long endIndex;private String path;public DownloadThread(String path, int threadId, long startIndex,long endIndex) {this.path = path;this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;}@Overridepublic void run() {try {// 当前线程下载的总大小int total = 0;File positionFile = new File(Environment.getExternalStorageDirectory(),getFileName(path)+threadId + ".txt");URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");// 接着从上一次的位置继续下载数据if (positionFile.exists() && positionFile.length() > 0) {// 判断是否有记录FileInputStream fis = new FileInputStream(positionFile);BufferedReader br = new BufferedReader(new InputStreamReader(fis));// 获取当前线程上次下载的总大小是多少String lasttotalstr = br.readLine();int lastTotal = Integer.valueOf(lasttotalstr);System.out.println("上次线程" + threadId + "下载的总大小:"+ lastTotal);startIndex += lastTotal;total += lastTotal;// 加上上次下载的总大小。fis.close();//存数据库。//_id path threadid total}conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);conn.setConnectTimeout(5000);int code = conn.getResponseCode();System.out.println("code=" + code);InputStream is = conn.getInputStream();File file = new File(Environment.getExternalStorageDirectory(),getFileName(path));RandomAccessFile raf = new RandomAccessFile(file, "rw");// 指定文件开始写的位置。raf.seek(startIndex);System.out.println("第" + threadId + "个线程:写文件的开始位置:"+ String.valueOf(startIndex));int len = 0;byte[] buffer = new byte[1024];while ((len = is.read(buffer)) != -1) {RandomAccessFile rf = new RandomAccessFile(positionFile,"rwd");raf.write(buffer, 0, len);total += len;rf.write(String.valueOf(total).getBytes());rf.close();pbs.get(threadId-1).setProgress(total);}is.close();raf.close();} catch (Exception e) {e.printStackTrace();Message msg = Message.obtain();msg.what = THREAD_ERROR;handler.sendMessage(msg);} finally {// 只有所有的线程都下载完毕后 才可以删除记录文件。synchronized (MainActivity.class) {System.out.println("线程" + threadId + "下载完毕了");runningThreadCount--;if (runningThreadCount < 1) {System.out.println("所有的线程都工作完毕了。删除临时记录的文件");for (int i = 1; i <= threadCount; i++) {File f = new File(Environment.getExternalStorageDirectory(),getFileName(path)+ i + ".txt");System.out.println(f.delete());}Message msg = Message.obtain();msg.what = DWONLOAD_FINISH;handler.sendMessage(msg);}}}}}//http://192.168.1.100:8080/aa.exeprivate String getFileName(String path){int start = path.lastIndexOf("/")+1;return path.substring(start);}}

利用XUtils开源框架实现,需要XUtils的jar包

public class MainActivity extends Activity {private EditText et_path;private TextView tv_info;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);tv_info = (TextView) findViewById(R.id.tv_info);}public void download(View view){String path = et_path.getText().toString().trim();if(TextUtils.isEmpty(path)){Toast.makeText(this, "请输入下载的路径", 0).show();return;}else{HttpUtils http = new HttpUtils();HttpHandler handler = http.download(path,"/sdcard/xxx.zip",true, // 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。true, // 如果从请求返回信息中获取到文件名,下载完成后自动重命名。new RequestCallBack<File>() {@Overridepublic void onStart() {tv_info.setText("conn...");}@Overridepublic void onLoading(long total, long current, boolean isUploading) {tv_info.setText(current + "/" + total);}@Overridepublic void onSuccess(ResponseInfo<File> responseInfo) {tv_info.setText("downloaded:" + responseInfo.result.getPath());}@Overridepublic void onFailure(HttpException error, String msg) {tv_info.setText(msg);}});}}
}

完成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

量子计算赛道上的巨头拉锯战

来源&#xff1a;网易智能据国外媒体报道&#xff0c;长期以来量子计算机一直被吹捧为功能强大得令人难以置信的机器。相比于世界上现有的计算机&#xff0c;量子计算机能够以更快的速度解决极其复杂的计算问题。但目前还没有就开发量子计算机的最佳方式达成一致。最终谁将赢得…

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 22丨平均售价【难度中等】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

Android之Intent深入

Android中的意图包含多种用法&#xff0c;本文主要包括以下内容 显式意图 隐匿意图 要求结果回传的意图 显式意图 &#xff1a;必须指定要激活的组件的完整包名和类名 &#xff08;应用程序之间耦合在一起&#xff09; 一般激活自己应用的组件的时候 采用显示意图 隐式意…

信通院AI白皮书:硬核干货一文打尽,从技术流派到应用趋势【附下载】

来源&#xff1a;智东西摘要&#xff1a;从产业发展的角度&#xff0c;分析AI技术现状、问题以及趋势&#xff0c;盘点智能语音、语义理解、计算机视觉等相关应用。自2016年AlphaGo击败李世石之后&#xff0c;人工智能&#xff08;AI&#xff09;这个再度翻红的科技热词已经在争…

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 23丨向CEO汇报工作的人【难度中等】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

正则学习笔记

用途 字符匹配 语法 常用元字符 []    区间范围框 枚举值  [a-z0-9A-Z_] |    分枝条件或 \    特殊转义符&#xff08;取消转义&#xff09; \W [^A-Za-z0-9_] [\r\n] 换行符匹配 [\u4e00-\u9fa5] 汉字 [\s\S] 任意字符 限定符 贪婪匹配&…

Android之UI控件

本文主要包括以下内容 Spinner的使用 Gallery的使用 Spinner的使用 Spinner的实现过程是 1. 在xml文件中定义Spinner的控件 2. 在activity中获取Spinner控件 3. 定义Spinner下拉列表项数组并将下拉项的内容添加到这个数组中&#xff0c;通过这个数组建立一个下拉列表的适…

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 23丨学生们参加各科测试的次数【难度简单】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

大脑如何判断该睡觉了?可能是这80种蛋白说了算

来源&#xff1a;科研圈撰文&#xff1a;Veronique Greenwood翻译&#xff1a;石云雷编辑&#xff1a;戚译引睡眠对于正常的学习和身体健康至关重要&#xff0c;但科学家们仍未完全了解睡眠在恢复大脑功能方面的作用和我们会感到困倦的原因。而通过对基因突变小鼠不寻常睡眠需求…

ImageLoader实现图片异步加载

ImageLoader是一个广泛使用的图片库,在向网络请求图片时&#xff0c;使用imageView和smartView常会产生outofmemory错误&#xff0c;这时ImageLoader可以起到很大的作用&#xff0c;主要有如下功能 一、功能特性&#xff1a; 多线程异步加载和显示图片&#xff08;图片来源于…

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 26丨广告效果【难度简单】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

AI芯片最新格局分析

来源&#xff1a;中金公司&#xff0c;作者黄乐平、何玫与杨俊杰AI 芯片设计是人工智能产业链的重要一环。 自 2017 年 5 月以来&#xff0c;各 AI 芯片厂商的新品竞相发布&#xff0c;经过一年多的发展&#xff0c;各环节分工逐渐明显。 AI 芯片的应用场景不再局限于云端&…

原理图学习笔记一

画个草图也挺过瘾 转载于:https://www.cnblogs.com/retacn-yue/archive/2013/02/17/3263137.html

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 27丨每次访问的交易次数【难度困难-提前放出来】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

Android Studio安装与配置

谷歌已经停止支持eclipse开发android了&#xff0c;转向android studio是大势所趋&#xff0c;笔者由于电脑配置的原因&#xff0c; 以前迟迟不愿意向android studio&#xff0c;现如今因为开始学习material design,不得不转向android studio了&#xff0c; 费了一番功夫&…

材料界的魔术师:值得关注的10家超材料创业公司

来源&#xff1a;资本实验室超材料是具有人工设计的结构并呈现出天然材料所不具备的超常物理性质的人工复合结构或复合材料。典型的超材料有&#xff1a;“左手材料”、光子晶体、“超磁性材料”等。通俗地说&#xff0c;通过超材料技术&#xff0c;我们将能够摆脱来自自然界原…

ChildWindow在Open时旋转出现

在App.xaml中&#xff1a; <VisualState x:Name"Open"><Storyboard><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty"(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName"ContentRoot">&…

【每日SQL打卡】​​​​​​​​​​​​​​​DAY 24丨不同国家的天气类型【难度简单】​

【未来的你&#xff0c;会感谢今天努力的你】每日两题&#xff0c;一难一易&#xff0c;每天进步一点点&#xff0c;可能会直接导致一场面试的成功&#xff0c;或工作的轻松搞定&#xff0c;从而升职加薪迎娶白富美&#xff0c;加油小伙伴&#xff01; &#x1f345;举办场地&a…

Android之ScrollView

1、ScrollView和HorizontalScrollView是为控件或者布局添加滚动条 2、上述两个控件只能有一个孩子&#xff0c;但是它并不是传统意义上的容器 3、上述两个控件可以互相嵌套 4、滚动条的位置现在的实验结果是&#xff1a;可以由layout_width和layout_height设定 5、ScrollV…

百余位中外学者探讨神经科技挑战:伦理担忧与监管难题并存

来源&#xff1a;澎湃新闻“脑电图图纸也许会读出人的意识”、“脑机接口技术可能使个人的行为被他人操纵”、“人造大脑的发明可能取代人类的角色”……这些形形色色的言论道出了人们对于神经科学的道德和伦理担忧。澎湃新闻专访了神经伦理学领域的研究人员&#xff0c;就神经…