android多线程断点下载

多线程断电xia下载,通过设置线程的数量,动态获取下载文件线程的个数,这是本人用于练习所写demo,注释很详细,用于初学者参考使用。

MainActivity.java页面

 

package com.dahui.download;

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.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_threadCount;
	private LinearLayout ll_pb_layout;
	private String path;
	private static int runningThread;  //代表当前正在运行的线程
	private int threadCount;
	private List<ProgressBar> pbList;//用来存进度条的引用

	@Override
	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_pb);
		
		pbList = new ArrayList<ProgressBar>();
	}
	
	//点击下载按钮
    public void click(View v){
    	path = et_path.getText().toString().trim();
    	//[3]获取线程数量
    	String threadCountt = et_threadCount.getText().toString().trim();
    	//[3.1]先移除之前添加的进度条
    	ll_pb_layout.removeAllViews();
    	threadCount = Integer.parseInt(threadCountt);
    	
    	pbList.clear();//每次点击清空集合
    	
    	for (int i = 0; i < threadCount; i++) {
    		//[3.1]把定义的item布局转换成view对象
    		ProgressBar pbView = (ProgressBar) View.inflate(getApplicationContext(), R.layout.item, null);
    		
    		//[3.2]把pbView添加到集合中
    		pbList.add(pbView);
    		
			//[4]动态添加进度条
    		ll_pb_layout.addView(pbView);
		}
    	//[5]开始移植 联网
    	new Thread(){public void run() {

    		//【1】★★★★★★获取服务器文件大小  要计算每个线程开始位置和结束位置
    		try {
    			//String path = "http://192.168.231.2:8080/new1.xml";
    			URL url = new URL(path);
    			//[2.3]拿到HttpURLConnection对象    用于发送或接受数据
    			HttpURLConnection coon = (HttpURLConnection) url.openConnection();
    			//[2.4]设置发送get请求
    			coon.setRequestMethod("GET");//get大写 默认就是get
    			//请求超时时间
    			coon.setConnectTimeout(5000);
    			//[2.6]获取服务器返回的状态码
    			int code = coon.getResponseCode();
    			//[2.7]如果code==200 说明请求成功
    			if (code == 200) {
    				int length = coon.getContentLength();
    				
    				runningThread = threadCount; //把线程的数量赋值给正在运行的线程
    				
    				System.out.println("length"+length);
    				//【2】★★★★★★创建一个大小和服务器一模一样的文件  目的是把空间提前申请出来
    				RandomAccessFile rafAceAccessFile = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path), "rw");
    				rafAceAccessFile.setLength(length);
    				
    				//算出每个线程下载的大小
    				int blockSize = length / threadCount;
    				
    				//【3】★★★★★★计算每个线程开始位置和结束位置
    				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);
    					
    					//【4】★★★★★★开启线程去服务器下载文件
    					DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
    					downLoadThread.start();
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	
    	};}.start();
    	
    }
    public String getFilename(String path){
		int start = path.lastIndexOf("/")+1;
		return path.substring(start);
	}
    
    private class DownLoadThread extends Thread{
		//通过构造方法把每个线程下载的开始位置和结束位置传递出来
		private int startIndex;
		private int endIndex;
		private int threadId;
		private int PbMaxSize; //代表当前线程下载的最大值
		//如果中断过   则获取上次下载位置
		private int pblastposition;
		
		public DownLoadThread(int startIndex,int endIndex,int threadId){
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
			
		}
		@Override
		public void run() {
			//实现去服务器下载文件的逻辑
			try {
				
				//[0]计算当前进度条的最大值
				PbMaxSize = endIndex-startIndex;
				URL url = new URL(path);
				//[2.3]拿到HttpURLConnection对象    用于发送或接受数据
				HttpURLConnection coon = (HttpURLConnection) url
						.openConnection();
				//[2.4]设置发送get请求
				coon.setRequestMethod("GET");//get大写 默认就是get
				//请求超时时间
				coon.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 buff = new BufferedReader(new InputStreamReader(fis));
					String lastPositionn = buff.readLine();//读取出来的内容就是上一次下载的位置
					int lastPosition = Integer.parseInt(lastPositionn);
					
					//★★给我们定义的进度条赋值
					pblastposition = lastPosition - startIndex;
					
					//☆☆☆☆☆☆要改变一下startIndex位置
					startIndex = lastPosition;
					System.out.println("线程Id:"+threadId +"真实下载位置"+":"+startIndex+"-----"+endIndex);
					fis.close();
				}
				
				
				
				
				//设置请求头Range (告诉服务器每个线程的开始下载和结束位置)
				coon.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
				
				//[2.6]获取服务器返回的状态码
				int code = coon.getResponseCode();
				//[2.7]如果code==200 说明请求成功 206代表请求部分资源成功
				if (code == 206) {
					
					//创建随机读写文件对象
					RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path), "rw");
					//每个线程从自己的位置开始写
					raf.seek(startIndex);
					
					//[2.8]获取服务器返回的数据   以流的形式返回(要把流转换成字符串,此操作比较常见,所以把它做成工具类)
					InputStream in = coon.getInputStream();//存的是UCBrowser.exe
					
					//9把数据写到文件中
					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;
						//10.实现断点续传   记录当前下载的位置
						int currentThreadPosition = startIndex+total;//把这个位置存起来
						//11.用来存当前线程下载的位置
						RandomAccessFile raff = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path)+threadId+".txt", "rwd");
						raff.write(String.valueOf(currentThreadPosition).getBytes());
						raff.close();
						
						//设置进度条的最大值和最小值
						pbList.get(threadId).setMax(PbMaxSize);//设置进度条最大值
						pbList.get(threadId).setProgress(pblastposition+total);//设置进度条当前进度
						
						
					}
					raf.close(); //关闭流 释放资源
					System.out.println("线程id:"+threadId+"----下载完毕!");
					
					//下载完毕删除断点保存的.txt文件
					synchronized (this) {
						runningThread--;
						if(runningThread == 0){
							//说明所有线程执行完毕
							for (int i = 0; i < threadCount; i++) {
								File delteFile = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path)+i+".txt");
								delteFile.delete();
							}
						}
					}
					
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

 布局页面:activity_main.xml页面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

	<EditText 
	    android:id="@+id/et_path"
	    android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="http://192.168.231.2:8080/UCBrowser.exe"
        android:hint="请输入下载的路径"
	    />
	
	<EditText 
	    android:id="@+id/et_threadCount"
	    android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入线程的数量"
	    />
	
	<Button 
		android:onClick="click"
	    android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"
	    />
	<LinearLayout 
	    android:id="@+id/ll_pb"
	    android:background="#080E12"
	    android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
	    >
	    
	    
	</LinearLayout>
</LinearLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
    <ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />


结果截图:

资源源码包下载地址:https://download.csdn.net/download/qq_38993002/10759021

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值