关闭

多线程下载并且实现断点下载

标签: androidjava多线程多线程下载以及断点下载
271人阅读 评论(0) 收藏 举报
分类:

1.至于为什么要用多线程下载,无非就是为了提高下载速度至于为什么会提高下载速度,就像两个人去搬一件东西总比一个人搬东西要快是吧,所以多线程也是同样的道理,开两个线程去下载一份资源肯定要比开一个线程去下载资源要快,至于其中的真正原理就不多说了!感兴趣的可以去研究下!

2.在实际应用下载资源时往往需要实现断点下载,保证用户意外终止下载后还可以接着上次的下载进度继续进行下载,这样就不用因为一次意外终止后又要重新下载了!

3.一份资源要开启多个线程去下载,那就要确定每个线程要下载多少,从哪开始下载,从哪结束下载,只有这些都确定了才能实现开启多个线程去下载资源。

4.由于是在安卓中实现的多线程下载,接下来要实现断点下载,那就要借助安卓中每个应用程序自带的小型数据库SharedPreference来保存中断下载时刻已经下载了多少,这样在下次继续下载时就可以直接去数据库里取出上次的下载进度,接下来按这个进度继续下载,这样也就实现了断点下载了,但记得在下完了后要删除保存的进度数据,不然下次再去下载就无法下载了。如果是在Java中的话就可以在下载的位置再创建一个文件来保存下载进度,同样的道理,当下载完成了后也记得将那个文件删除。

5.还有一点是,在下载时应该先去获取要下载的资源的大小,然后用RandomAccessFile去下载的位置占取同样大小的空间,保证下载过程中不会因为空间不足而终止下载

//定义好要下载的位置以及占取要下载的文件的大小的地方
RandomAccessFile raFile=new RandomAccessFile(targetFile, "rwd");
raFile.setLength(fileSize);

6.说完原理后,接下来直接看源码吧!里面我定义了一个下载的工具类和自定义了一个线程去下载资源

<span style="font-size:18px;"><strong>package com.example.mulitThreadDownload;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;

public class DownUtil {
	//定义要下载的资源的url
	private String stringUrl;
	//指定要下载的位置
	private File targetFile;
	//定义需要使用多少条线程来下载资源
	private int threadNum;
	//定义下载的线程的对象
	private ThreadDown[] threads;
	//定以下载的文件的总大小
	private int fileSize;
	private Context context;
	public DownUtil(String stringUrl,File targetFile,int threadNum,Context context) {
		this.stringUrl=stringUrl;
		this.targetFile=targetFile;
		this.threadNum=threadNum;
		this.context=context;
		//初始化线程的数组
		this.threads=new ThreadDown[threadNum];
	}
	public void download() throws Exception{
		
		URL url=new URL(stringUrl);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setConnectTimeout(8000);
		conn.setReadTimeout(8000);
		conn.connect();
		if (conn.getResponseCode()==200) {
			fileSize=conn.getContentLength();
			conn.disconnect();
			int currentSize=fileSize/threadNum;
			//定义好要下载的位置以及占取要下载的文件的大小的地方
			RandomAccessFile raFile=new RandomAccessFile(targetFile, "rwd");
			raFile.setLength(fileSize);
			raFile.close();
			for(int i=0;i<threadNum;i++){
				//确定每个线程的下载的区间
				//开启对应的子线程
				int startPos=i*currentSize;
				int endPos=(i+1)*currentSize-1;
				if (i==threadNum-1) {
					endPos=fileSize-1;
				}
				//创建下载线程并启动它
				threads[i]=new ThreadDown(startPos, endPos,i,stringUrl,context);
				threads[i].start();
				//System.out.println("第"+i+"个线程的下载区间为"+startPos+"-"+endPos);
			}
		}
	}
	public double getComplete(){
		//统计多条线程已经下载的总大小
		int sumSize=0;
		for (int i = 0; i < threadNum; i++) {
			sumSize+=threads[i].hasDownLength;
		}
		//返回已经完成的百分比
		return sumSize*1.0/fileSize;
	}
}</strong></span>

自定义线程:

package com.example.mulitThreadDownload;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.content.SharedPreferences;

public class ThreadDown extends Thread{
	//定义sharedPreference来保存下载的进度
	private SharedPreferences preferences;
	private SharedPreferences.Editor editor;
	private int startPos,endPos,threadId;
	//下载的文件的url
	private String stringUrl;
	//定义该线程已经下载的长度
	public int hasDownLength;
	private Context context;
	private int lastPos;
	
	public ThreadDown(int startIndex,int endIndex,int threadId,String stringUrl,Context context) {
		this.startPos=startIndex;
		this.endPos=endIndex;
		this.threadId=threadId;
		this.stringUrl=stringUrl;
		this.context=context;
	}
	@Override
	public void run() {
		try {
			preferences=context.getSharedPreferences("progress",Context.MODE_PRIVATE);
			if ((lastPos=preferences.getInt(threadId+"", 0))!=0) {
				startPos+=lastPos;
			}
			URL url=new URL(stringUrl);
			HttpURLConnection conn=(HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(8000);
			conn.setReadTimeout(8000);
			//设置连接头部的一些信息,设置下载的范围
			conn.setRequestProperty("Range","bytes="+startPos+"-"+endPos);
			conn.connect();
			if (conn.getResponseCode()==206) {
				InputStream is=conn.getInputStream();
				File file=new File("mnt/sdcard/NBA.zip");
				RandomAccessFile raf=new RandomAccessFile(file, "rwd");
				//跳到指定位置开始下载
				raf.seek(startPos);
				byte[] buffer=new byte[1024];
				int hasRead=0;
				hasDownLength=lastPos;
				while((hasRead=is.read(buffer))!=-1){
					raf.write(buffer, 0, hasRead);
					//累计该线程下载的总大小
					hasDownLength+=hasRead;
					//System.out.println("第"+threadId+"条线程下载了"+hasDownLength);
					///获取只能被本应用程序读写的SharedPreference对象
					editor=preferences.edit();
					editor.putInt(threadId+"", hasDownLength).commit();
				}
				raf.close();
				is.close();
				System.out.println("第"+threadId+"条线程下载完成了!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}	

接下来是主Activity类,里面只是简单的放了一个进度条显示下载进度,两个按钮开始和暂停下载,其中暂停下载我是通过直接终止程序来中断了下载,一个TextView来显示下载的百分比!

<span style="font-size:18px;"><strong>package com.example.mulitThreadDownload;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
	private static final String STRINGURL="http://192.168.46.2:8080/NBA_CN_app.zip";
	private File file;
	//开启几个线程去下载资源
	private int threadNum=4;
	private DownUtil downUtil;
	//定义当前的下载进度
	private int downRate;
	//每个线程的开始下载位置和结束下载位置
	private ProgressBar pb;
	private TextView downTv;
	private Handler handler=new Handler(){
		public void handleMessage(android.os.Message msg) {
			if (msg.what==0x123) {
				//更新进度条,以及跟新下载完成的百分比
				pb.setProgress(downRate);
				downTv.setText("已下载"+downRate+"%");
			}
		};
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		pb=(ProgressBar)findViewById(R.id.pb);
		downTv=(TextView)findViewById(R.id.down_tv);
		file=new File("mnt/sdcard/NBA.zip");
	}

	public void start(View view){
		downUtil=new DownUtil(STRINGURL, file, threadNum,this);
		new Thread(){
			public void run() {
				try {
					///开始下载
					downUtil.download();
				} catch (Exception e) {
					e.printStackTrace();
				}
				//定义每秒调度获取一次系统的完成进度
				final Timer timer=new Timer();
				timer.schedule(new TimerTask() {
					@Override
					public void run() {
						//获取下载任务的完成比例
						double completeRate=downUtil.getComplete();
						downRate=(int)(completeRate*100);
						//发送消息通知界面更新进度条
						handler.sendEmptyMessage(0x123);
						//下载完成后取消任务调度
						if (downRate>=100) {
							timer.cancel();
							MainActivity.this.getSharedPreferences("progress", Context.MODE_PRIVATE)
							.edit().clear().commit();
						}
					}
				}, 0, 1000);
			};
		}.start();
	}
	public void pause(View view){
		System.exit(0);
	}
}
</strong></span>




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:11459次
    • 积分:304
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:0篇
    • 译文:0篇
    • 评论:3条
    最新评论