Android多线程断点下载

先在j2SE编写代码(调试方便),后移值Android中


1.看图应该比较容易理解:

2.先要注意的是:


// 注意此处,指定请求的范围

conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);

// 注意此处,状态是206表示(部分内容) 服务器成功处理了部分 GET 请求。

if (code == 206)

// 判断是否存在上一次下载好记录,若有该记录,把记录添加到当前线程的起始位置

if (file.exists() && file.length() > 0) 

//获取LinearLayout里的子View

pb = (ProgressBar) linearLayout.getChildAt(threadId);

// 线程之间的同步,确保删除文件

synchronized (MainActivity.class)


3.源代码:


布局文件

<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="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dip"
        android:layout_marginRight="5dip"
        android:text="@string/path" />


    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dip"
        android:layout_marginRight="5dip"
        android:onClick="downLoader"
        android:text="DownLoad" />


    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="5dip"
        android:layout_marginRight="5dip"
        android:orientation="vertical" >


        <ProgressBar
            android:id="@+id/progressBar1"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <ProgressBar
            android:id="@+id/progressBar2"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <ProgressBar
            android:id="@+id/progressBar3"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
       
    </LinearLayout>


</LinearLayout>


源代码

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 android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends Activity {

	private static EditText et;
	private static LinearLayout linearLayout;
	private static String path;
	private static int length; // 文件长度
	private static int threadCount = 3; // 线程数量
	private static int runingThreadCount = 3; // 用于删除断点下载的记录文件
	private ProgressBar progressBar1, progressBar2, progressBar3;
	SharedPreferences sp;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		et = (EditText) findViewById(R.id.et_path);
		linearLayout = (LinearLayout) findViewById(R.id.linear);
		progressBar1 = (ProgressBar) findViewById(R.id.progressBar1);
		progressBar2 = (ProgressBar) findViewById(R.id.progressBar2);
		progressBar3 = (ProgressBar) findViewById(R.id.progressBar3);
		sp = getSharedPreferences("progress", Context.MODE_PRIVATE);
		int firstposition = sp.getInt("0downloadPosition", 0);
		int firsttotal = sp.getInt("0total", 0);
		int secondposition = sp.getInt("1downloadPosition", 0);
		int secondtotal = sp.getInt("1total", 0);
		int thirdposition = sp.getInt("2downloadPosition", 0);
		int thirdtotal = sp.getInt("2total", 0);
		progressBar1.setMax(firsttotal);
		progressBar1.setProgress(firstposition);
		progressBar2.setMax(secondtotal);
		progressBar2.setProgress(secondposition);
		progressBar3.setMax(thirdtotal);
		progressBar3.setProgress(thirdposition);

	}

	public void downLoader(View view) {
		path = et.getText().toString().trim();
		if (TextUtils.isEmpty(path)) {
			Toast.makeText(this, "路径资源不能为空", 0).show();
			return;
		}

		new Thread() {
			public void run() {

				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url
							.openConnection();
					conn.setRequestMethod("GET");
					int code = conn.getResponseCode();
					if (code == 200) {
						length = conn.getContentLength();
						// 1.创建与目标文件相同大小的空文件
						RandomAccessFile raf = new RandomAccessFile(Environment
								.getExternalStorageDirectory().getPath()
								+ "/"
								+ getFileName(path), "rw");
						raf.setLength(length);
						System.out.println("文件长度为:" + length);
						raf.close();
					} else {
						System.out.println("获取数据失败");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				// 2.开启多线程下载,并分配每个线程的下载的区块
				int BlockSize = length / threadCount;
				for (int threadId = 0; threadId < threadCount; threadId++) {
					// 每个线程的下载区块的起始、结束位置
					int startIndex = threadId * BlockSize;
					int endIndex = (threadId + 1) * BlockSize - 1;
					// 最后一个线程下载多余的byte
					if (threadId == threadCount - 1) {
						endIndex = length - 1;
					}
					System.out.println("线程" + threadId + ":起始位置" + startIndex
							+ ":结束位置" + endIndex);
					new DownThread(startIndex, endIndex, threadId,
							MainActivity.this).start();
				}
			};
		}.start();
	}

	static class DownThread extends Thread {
		private int startIndex;
		private int endIndex;
		private int threadId;
		private int recordDownloadPosition; // 断点下载,记录上次下载好的长度
		private ProgressBar pb;
		Context context;
		private int total;

		/**
		 * @param startIndex
		 *            起始位置
		 * @param endIndex
		 *            结束位置
		 * @param threadId
		 *            标识线程Id
		 */
		public DownThread(int startIndex, int endIndex, int threadId,
				Context context) {
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
			this.context = context;
			this.total = endIndex - startIndex;
			//获取LinearLayout里的子View
			pb = (ProgressBar) linearLayout.getChildAt(threadId);
			pb.setMax(total);
			System.out.println("线程" + threadId + "设置总大小"
					+ (endIndex - startIndex));
		}

		@Override
		public void run() {

			try {

				File file = new File(Environment.getExternalStorageDirectory()
						.getPath() + "/" + threadId + ".txt");
				// 判断是否存在上一次下载好记录,若有该记录,把记录添加到当前线程的起始位置
				if (file.exists() && file.length() > 0) {
					FileInputStream fis = new FileInputStream(file);
					BufferedReader sb = new BufferedReader(
							new InputStreamReader(fis));
					String countStr = sb.readLine();
					recordDownloadPosition = Integer.parseInt(countStr);
					startIndex += recordDownloadPosition;
					fis.close();
					sb.close();
				}
				System.out.println("线程" + threadId + ":实际起始位置" + startIndex
						+ ":实际结束位置" + endIndex);
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				// 注意此处,指定请求的范围
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
						+ endIndex);
				int code = conn.getResponseCode();
				// 注意此处,状态是206表示(部分内容) 服务器成功处理了部分 GET 请求。
				if (code == 206) {
					InputStream is = conn.getInputStream();
					RandomAccessFile raf = new RandomAccessFile(Environment
							.getExternalStorageDirectory().getPath()
							+ "/"
							+ getFileName(path), "rwd");
					raf.seek(startIndex);
					byte[] buffer = new byte[1024 * 100];
					int len = -1;
					while ((len = is.read(buffer)) != -1) {
						recordDownloadPosition += len;
						// 此处使用RandomAccessFile,为了确保把数据写到文件中,使用普通File可能写不了数据到文件
						RandomAccessFile recordraf = new RandomAccessFile(
								Environment.getExternalStorageDirectory()
										.getPath() + "/" + threadId + ".txt",
								"rwd");
						//设置进度
						pb.setProgress(recordDownloadPosition);
						//以xml格式保存当前进度,用于下次回显该进度
						SharedPreferences spf = context.getSharedPreferences(
								"progress", Context.MODE_PRIVATE);
						Editor editor = spf.edit();
						editor.putInt(threadId + "downloadPosition",
								recordDownloadPosition);
						editor.putInt(threadId + "total", total);
						editor.commit();
						recordraf.write(String.valueOf(recordDownloadPosition)
								.getBytes());
						raf.write(buffer, 0, len);
						recordraf.close();
					}
					is.close();
					raf.close();
					System.out.println("线程" + threadId + "下载完毕");
					// 线程之间的同步,确保删除文件
					synchronized (MainActivity.class) {
						runingThreadCount--;
						if (runingThreadCount == 0) {
							for (int i = 0; i < threadCount; i++) {
								File ff = new File(Environment
										.getExternalStorageDirectory()
										.getPath()
										+ "/" + i + ".txt");
								System.out.println(ff.delete());
							}
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 截取文件名
	 * 
	 * @param path
	 *            路径
	 * @return 返回目标文件名
	 */
	private static String getFileName(String path) {
		int index = path.lastIndexOf("/") + 1;
		String fileName = path.substring(index);
		return fileName;
	}

}

效果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值