Android多线程加速下载

包含断点续传,以下代码只是核心思路,并不健壮

package com.itheima.mutildownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

	private EditText et_path;
	private EditText et_thread_number;
	private LinearLayout ll;

	private  int threadCount;  //线程的个数 
	private static int runningThread;  //正在运行的线程 
	private List<ProgressBar> pbs;     //存进度条的引用 
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//下载的路径 
		
		et_path = (EditText) findViewById(R.id.et_path);   
		//下载的线程个数 
		
		et_thread_number = (EditText) findViewById(R.id.et_thread_number); 
		//来来存放 进度条
		ll = (LinearLayout) findViewById(R.id.ll);    
		
		pbs = new ArrayList<ProgressBar>();
		
		
		
	}
	
	/**
	 * 点击 按钮  进行下载的逻辑 
	 * @param v
	 */
	public void click(View v){
		//拿到 下载的路径 和 线程的个数 
		String path = et_path.getText().toString().trim();
		
		String number = et_thread_number.getText().toString().trim();  //线程的个数 
		threadCount = Integer.parseInt(number);
  		ll.removeAllViews();
  		pbs.clear();
		for (int i = 0; i < threadCount; i++) {
			//动态的加载进度条 
			ProgressBar pb =  (ProgressBar) View.inflate(getApplicationContext(), R.layout.pb, null);
			ll.addView(pb);
		
			pbs.add(pb);  //加入集合中
			
		}

		
		//1获取到服务器资源的大小  
		try {
			URL url = new URL(path);
			//打开一个url连接 
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			//设置conn 的参数 
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(5000);
			//获取服务器返回的状态码
			int code = conn.getResponseCode();
			if (code == 200) { //200 请求服务器资源全部返回成功     //206 请求部分服务器资源返回成功   
				//获取到服务器资源的大小 
				int length = conn.getContentLength();

				runningThread = threadCount;
				//2 创建一个大小和服务器一模一样的文件    rw模式 
				RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path), "rw");
				raf.setLength(length);
				
				//每个线程下载的大小是多少 
				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);
					//3 开启多个线程 
					DownLoadThread downLoadThread = new DownLoadThread(path, startIndex, endIndex,i);
					downLoadThread.start();
				}

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	
	
	//这个是我线程真正下载的类 
		public  class DownLoadThread extends Thread{
			private String path;  //下载路径
			private int startIndex;
			private int endIndex;
			private int threadId; 
			
			private int pbmaxprogress;
			
			private int lastdownLoadSize;  //上一次下载的大小 
			
			public DownLoadThread(String path,int startIndex,int endIndex, int threadId){
				this.path = path;
				this.startIndex = startIndex;
				this.endIndex = endIndex;
				this.threadId = threadId;
				
			}
			
			@Override
			public void run() {
				
				try {
					pbmaxprogress = endIndex - startIndex;
					
					URL url = new URL(path);
					//打开一个url连接 
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					//设置conn 的参数 
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(5000);
					
					//判断一下 是否存在下载记录  
					File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+threadId+".txt");
					if (file.exists() && file.length()>0) {
						//说明已经下载过
						FileInputStream fis = new FileInputStream(file);
						BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
						String lastPosition = bufr.readLine(); //上次我保存的位置  
						
						//从lastPosition 位置开始 
						conn.setRequestProperty("Range", "bytes="+lastPosition+"-"+endIndex);
						//上次下载的大小
						lastdownLoadSize = Integer.parseInt(lastPosition)- startIndex; 
						//要改变一下 startindex的位置 
						startIndex = Integer.parseInt(lastPosition);
						fis.close();
						System.out.println("线程id~"+threadId+"真实下载的位置-"+startIndex+"--"+endIndex);
						
						
					}else {
						//开多个线程去下载  设置一个头信息  Range  去服务器  取部分数据   从startIndex 开启取  取到 endIndex结束
						conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
					}
					
					//获取服务器返回的状态码
					int code = conn.getResponseCode();
					if (code == 206) { //200 请求服务器资源全部返回成功     //206 请求部分服务器资源返回成功   
						InputStream inputStream = conn.getInputStream(); //获取服务器返回的数据 
						RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path), "rw");
						raf.seek(startIndex); //设置指针偏移量  从 startindex 位置开始读
						int len = -1;
						byte buffer[]  = new byte[1024*1024];
						
						//做断点续传 首先我们要把每个线程 下载的位置 存起来   
						int total = 0;
						
						while((len=inputStream.read(buffer))!=-1){
							
							raf.write(buffer, 0, len);
							
							total+=len; //当前线程下载的总大小 
							int currentThreadPosition = startIndex + total; //把当前线程下载的位置给保存起来 
							//怎么保存  保存到哪里 
							RandomAccessFile raff = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+threadId+".txt", "rwd");
							raff.write(String.valueOf(currentThreadPosition).getBytes());
							raff.close();
							
							// 更新进度条     
							pbs.get(threadId).setMax(pbmaxprogress); //设置进度条的最大值
							pbs.get(threadId).setProgress(lastdownLoadSize+total); //设置当前的进度条的进度 
							
							
						}
						raf.close();
						inputStream.close();
						//说明 所有的线程都下载完毕了 
						System.out.println("线程id~"+threadId+"下载ok");
						
						synchronized (DownLoadThread.class) {
							runningThread--;
							if (runningThread <= 0) {
								// 说明所有的线程都下载完毕了
								for (int i = 0; i < threadCount; i++) {
									File deleteFile = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+i+".txt");
									deleteFile.delete();
								}
								

							}
						}

					}

				} catch (Exception e) {
					e.printStackTrace();
				}
				
				
				super.run();
			}
			
		}
		
		//获取路径的名称 
		public static String getFileName(String path){
			 int start = path.lastIndexOf("/")+1;
			 return path.substring(start);
			 
		}
		
	
	
	
	
	
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可 6私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Barry__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值