安卓笔记4--多线程断点续传

多线程断点续传无论在什么平台上都是极为重要的,这部分知识非常重要。老规矩,用一张图来介绍今天的内容。

图片看不清的话可以右键新窗口打开

原理的话也很简单多线程就是将一个文件分成不同部分让多个线程直接下载,断点续传使用一个文本记录当前下载量,再开始的时候读取文本下载值就可以了。

直接看代码吧

public class MainActivity extends Activity {
	 String path = "http://192.168.15.77:8080/QQPlayer.exe";
	 int threadCount = 3;
	 int finishedThreadCount = 0;
	 int currentPbProgress;
	private ProgressBar pb;
	private TextView tv;

	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			tv.setText((long)pb.getProgress() * 100 / pb.getMax() + "%");
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		//进度条用于显示当前下载进度,下载的总字节数作为progress,目标文件的总大小作为max
		pb = (ProgressBar) findViewById(R.id.pb);
		tv = (TextView) findViewById(R.id.tv);
	}

	public void click(View v){
		Thread t = new Thread(){
			@Override
			public void run() {
				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(8000);
					conn.setReadTimeout(8000);

					if(conn.getResponseCode() == 200){
						//拿到要下载的文件的总长度
						int length = conn.getContentLength();

						//在本地生成一个临时文件,临时文件大小与目标文件大小一致
						File file= new File(Environment.getExternalStorageDirectory(), getFileName(path));
						RandomAccessFile raf = new RandomAccessFile(file, "rwd");
						raf.setLength(length);
						raf.close();

						//设置进度条的总进度为目标文件总长
						pb.setMax(length);

						//计算每条线程要下载的长度
						int size = length / threadCount;
						//计算每条线程的开始位置与结束位置
						for(int i = 0; i < threadCount; i++){
							int startIndex = i * size;
							int endIndex = (i + 1) * size - 1;
							if( i == threadCount - 1)
								endIndex = length - 1;

//							System.out.println("线程" + i + "的下载区间为:" + startIndex + "~" + endIndex);
							new DownLoadThread(startIndex, endIndex, i).start();
						}

					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		t.start();
	}
	String getFileName(String path){
		int index = path.lastIndexOf("/");
		return path.substring(index + 1);
	}

	class DownLoadThread extends Thread{

		int startIndex;
		int endIndex;
		int threadId;

		public DownLoadThread(int startIndex, int endIndex, int threadId) {
			super();
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
		}

		@Override
		public void run() {
			//开启子线程下载目标文件
			try {
				File fileProgess = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
				int lastTotal = 0;
				//判断文本临时文件是否存在
				if(fileProgess.exists()){
					FileInputStream fis = new FileInputStream(fileProgess);
					BufferedReader br = new BufferedReader(new InputStreamReader(fis));
					//获取上一下载的进度
					lastTotal = Integer.parseInt(br.readLine());

					//改变下载的开始位置,已经下载过的数据,就不要再去请求了
					startIndex += lastTotal;
					fis.close();

					//把上一次下载的总进度写入进度条
					currentPbProgress += lastTotal;
					pb.setProgress(currentPbProgress);
					handler.sendEmptyMessage(0);
				}
				System.out.println("线程" + threadId + "的最终下载区间为:" + startIndex + "~" + endIndex);
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(8000);
				conn.setReadTimeout(8000);
				//定义请求的数据的范围
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

				if(conn.getResponseCode() == 206){
					//流里的数据只有startIndex到endIndex区间的数据,并不会包含目标文件所有数据
					InputStream is = conn.getInputStream();

					byte[] b = new byte[1024];
					int len;
					int total = lastTotal;
					File file= new File(Environment.getExternalStorageDirectory(), getFileName(path));
					RandomAccessFile raf = new RandomAccessFile(file, "rwd");
					//改变往raf中写入数据的开始位置
					raf.seek(startIndex);

					while((len = is.read(b)) != -1){
						total += len;
						System.out.println("线程" + threadId + "已下载的字节数为:" + total);
						raf.write(b, 0, len);

						//为了完成断点续传,while循环每次下载的进度,都写入一个文本临时文件中
						RandomAccessFile rafProgress = new RandomAccessFile(fileProgess, "rwd");
						rafProgress.write((total + "").getBytes());
						rafProgress.close();

						currentPbProgress += len;
						//所有线程每次下载len个长度的字节,都会写到进度条的总进度中
						pb.setProgress(currentPbProgress);
						handler.sendEmptyMessage(0);
					}
					System.out.println("线程" + threadId + "下载完毕---------------------");
					raf.close();

					finishedThreadCount++;

					//三个线程全部下载完毕,才去删除文本临时文件
					synchronized (path) {
						if(finishedThreadCount == 3){
							for (int i = 0; i < threadCount; i++) {
								File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
								if(f.exists())
									f.delete();
							}
							finishedThreadCount = 0;
						}
					}
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
时间: 2024-10-25 13:24:24

安卓笔记4--多线程断点续传的相关文章

Android实现网络多线程断点续传下载

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 Ra

Android 多线程断点续传同时下载多个大文件

最近学习在Android环境中一些网络请求方面的知识,其中有一部分是关于网络下载方面的知识.在这里解析一下自己写的demo,总结一下自己所学的知识.下图为demo的效果图,仿照一些应用下载商城在ListView中列出加载项,然后可以可以下载和停止. 1.概述 这里有几个比较重要的类DownloadManager.DownloadService.DownloadTask.ThreadDAOImpl.主要的下载流程如下. (1) DownloadManager 负责下载任务的调配,以及下载服务Dow

Android实现多线程断点续传

前言: 项目都快交付阶段了,客户说要改个需求,添加一个断点续传功能.在版本更新,杂志下载或者视频下载的时候实现断点续传.由于时间紧迫,想起了之前研究过一个demo代码,就直接修改使用了,根据自己的方式实现,但是核心代码没变.以后或许会用到,于是就专门写了个demo. 先看一下项目目录结构: db--->操作数据库的(创建数据库表,数据的增删改查.) util--->工具类 download--->实现下载(下载器以及自定义线程.) 这里以易信客户端的下载为例,简要介绍. String d

【安卓笔记】抽屉式布局----DrawerLayout

效果如下: DrawerLayout来自support.v4包,所以不用考虑兼容性问题.其次,这种布局类似风靡一时的侧滑菜单,但是比侧滑菜单轻巧许多. 下面介绍这种布局的使用方式. 1.在你的项目中导入support.v4包. 2.编辑一个布局,根节点为android.support.v4.widget.DrawerLayout,此节点下只允许有两个子节点,第一个为将来主页面的内容,第二个节点即为"抽屉"内容,通常是一个ListView.比如: <android.support.

【安卓笔记】通过发送特定的短信远程控制手机

实现效果: 1.发送指令#*location*#,可以远程获取到手机的地理位置(经纬度),并以短信的形式返回. 2.发送指令#*locknow*#,可以远程锁屏并设置锁屏密码. 实现原理: 1.注册广播接受者,监听手机收到的短信,并对符合要求的特定短信进行拦截和处理. 2.通过LocationManager获取地理位置. 3.使用DevicePolicyManager实现锁屏.设置锁屏密码等操作. 步骤: 1.创建一个可以获取地理位置的工具类: package cn.edu.chd.mobile

Android多线程断点续传下载

这个月接到一个项目,要写一个像360助手一样的对于软件管理的APP:其中,遇到了一个问题:多线程断点下载 这个 ,由于之前没有写过这方面的应用功能.所以,不免要自学了.然后就在各个昂站上收索并整理了一下.跟大家分享一下,也能加深我在这方面的理解. 什么是多线程下载? 多线程下载其实就是迅雷,BT一些下载原理,通过多个线程同时和服务器连接,那么你就可以榨取到较高的带宽了,大致做法是将文件切割成N块,每块交给单独一个线程去下载,各自下载完成后将文件块组合成一个文件,程序上要完成做切割和组装的小算法

基于ibcurl的跨平台多线程断点续传下载库

之前写过一个多线程断点续传的下载库,不过那个是基于一个linux的下载程序.windows下运行还好,android下就各种问题,调试起来还麻烦.后面开发游戏的时候,一方面对下载要求不高,另一方面也精力有限,所以就没有继续研究. 趁现在有时间,我希望实现一个自己满意的下载库,满足以下需求: 1.多线程下载,根据文件大小和下载的文件数目进行调度.一般情况下是一个文件一个文件按照顺序下载,如果文件比较多的情况下可以多个文件同时下载,这个是可以设置的. 2.断点续传.下载进度记录到一个配置文件中,要求

Android实现网络多线程断点续传下载(转)

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是:  (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 R

《软件调试的艺术》笔记--调试多线程程序

下面是于线程相关的GDB命令用法汇总: info threads:给出关于当前所有线程的信息. thread 3:改成线程3. break 88 thread 3 :当线程到达源代码88时停止执行. break 88 thread 3 if i == 2 当线程3到达源代码行88行,并且变量i的值为2时停止执行. 对下面的多线程进行调试: #include <stdio.h> #include <pthread.h> #include <string.h> #inclu