android----断点多线程下载

在tomcat6.0的webapps\ROOT下放一个.exe的可执行文件(若放.mp3、.jpg等格式的文件可能下载过程出现损坏还是可以查看的,若是.exe可执行文件下载过程出现损坏就不可执行了),然后启动tomcat,双击bin文件夹下的startup.bat,出现以下的界面

记得不要关闭这个窗体,若关闭了后面的文件下载会出错的。

Android的布局文件代码如下:

<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:singleLine="true"
        android:text="http://172.29.168.1:8088/fengxing.exe" />

    <ProgressBar
        android:id="@+id/pb"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="28dp" />

    <Button
        android:id="@+id/bt"
        android:onClick="download"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="下载" />

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="目前下载的进度:" />

</LinearLayout>

效果如下图:

为了方便,在代码中写死了下载路径。

MainActivity中的代码如下:

package com.myself.download;

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

import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	protected static final int DOWN_LOAD_ERROR = 1;
	protected static final int SERVER_ERROR = 2;
	protected static final int SD_UNABLE = 3;
	public static final int DOWN_LOAD_FINISH = 4;
	public static final int UPDATE_TEXT = 5;
	public static int threadCount = 3;
    public static int runingThread =3;

    public int currentProcess=0;//当前的进度

	private EditText et_path;
	private ProgressBar pb;
	private TextView tv_show;

	private Handler handler=new Handler(){
         public void handleMessage(android.os.Message msg) {
        	 switch (msg.what) {
			case DOWN_LOAD_ERROR:
				Toast.makeText(MainActivity.this, "下载错误", 1).show();
				break;
			case SERVER_ERROR:
				Toast.makeText(MainActivity.this, "服务器连接错误", 1).show();
				break;
			case SD_UNABLE:
				Toast.makeText(MainActivity.this, "SD卡不可用", 1).show();
				break;
			case DOWN_LOAD_FINISH:
				Toast.makeText(MainActivity.this, "资源下载完毕", 1).show();
				break;
			case UPDATE_TEXT:
				tv_show.setText("目前下载的进度:"+pb.getProgress()*100/pb.getMax()+"%");
				break;
			default:
				break;
			}
         };
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		et_path=(EditText) findViewById(R.id.et_path);
		pb=(ProgressBar) findViewById(R.id.pb);
		tv_show=(TextView) findViewById(R.id.tv_show);
	}

	public void download(View v){
		final String path=et_path.getText().toString().trim();
		if(TextUtils.isEmpty(path)){
			Toast.makeText(this, "下载路径不能为空", 1).show();
			return ;
		}
		new Thread(){
			public void run() {
				// 1.连接服务器,获取要下载的文件长度,并创建一个跟要下载资源大小一样的临时文件
				try {

					//String path = "http://172.29.168.1:8088/fengxing.exe";
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setConnectTimeout(5000);
					conn.setRequestMethod("GET");
					int code = conn.getResponseCode();
					System.out.println("code:   "+code);
					if (code == 200) {
						// 服务器返回的数据的长度实际上就是文件的长度
						int length = conn.getContentLength();
						pb.setMax(length);
						//System.out.println("文件总长度:" + length);
						//判断sd卡是否可用
						if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
							//在客户端创建一个与要下载的资源同样大小的临时文件
							RandomAccessFile raf=new RandomAccessFile("/sdcard/fengxing.exe", "rwd");
							//设置文件的大小
							raf.setLength(length);
							raf.close();

							// 假设是3个线程去下载
							// 平均每一个线程下载的资源的大小
							int blockSize = length / threadCount;
							for (int threadId = 1; threadId <= threadCount; threadId++) {
								// 第一个线程开始下载的位置
								int startIndex = (threadId - 1) * blockSize;
								int endIndex = (threadId * blockSize) - 1;
								if (threadId == threadCount) {// 最后一个线程下载的资源就是剩下的资源
									endIndex = length;

								}
								System.out.println("线程"+threadId+"线程下载的位置: "+startIndex+"------->"+endIndex);
								new DownlLoad(threadId, startIndex, endIndex, path).start();

							}
						}else{
							System.out.println("sd卡不可用...");
							Message msg=new Message();
							msg.what=SD_UNABLE;
							handler.sendMessage(msg);
						}

					} else {
						System.out.println("服务器连接错误...");
						Message msg=new Message();
						msg.what=SERVER_ERROR;
						handler.sendMessage(msg);
					}

				} catch (Exception e) {
					e.printStackTrace();
					Message msg=new Message();
					msg.what=DOWN_LOAD_ERROR;
					handler.sendMessage(msg);
				}

			};
		}.start();
	}

	/**
	 * 下载文件的子线程   每一个线程下载对应位置的文件
	 * @author Administrator
	 *
	 */
	public class DownlLoad extends Thread{
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;

		/**
		 *
		 * @param threadId 线程Id
		 * @param startIndex  开始下载的位置
		 * @param endIndex  结束位置
		 * @param path 要下载的资源所在路径
		 */
		public DownlLoad(int threadId, int startIndex, int endIndex, String path) {
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.path = path;
		}

		@Override
		public void run() {
			try {
				//检查是否存在记录了已经下载长度的文件,若存在则读取文件的内容
				File tempFile=new File("/sdcard/"+threadId+".txt");
				if(tempFile.exists()&&tempFile.length()>0){
					FileInputStream fis=new FileInputStream(tempFile);

					byte[] temp=new byte[1024];
					int leng=fis.read(temp);
					String downloadLen=new String(temp,0,leng);
					int downloadInt=Integer.parseInt(downloadLen);

					int alreadyDownInt=downloadInt-startIndex;//已经下载的进度
					currentProcess+=alreadyDownInt;//若已经有下载的,重新设置进度

					startIndex=downloadInt;//修改下载真实的开始位置

				}

				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				//重要:请求服务器下载部分的文件  指定下载的资源范围
				conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
				System.out.println("线程"+threadId+"线程重新开始下载的位置: "+startIndex+"------->"+endIndex);
				int code = conn.getResponseCode();//200代表的是全部的资源     206代表的是部分资源

				//System.out.println("code:"+code);
				if(code==206){
					InputStream is=conn.getInputStream();//已经设置了请求的位置  返回当前位置对应的文件的输入流
					RandomAccessFile raf=new RandomAccessFile("/sdcard/fengxing.exe", "rwd");
					raf.seek(startIndex);//定位开始位置

					int len=0;
					byte[] buff=new byte[1024];

					int total=0;//记录已经下载的文件的长度

					while((len=is.read(buff))!=-1){
						//FileOutputStream fos=new FileOutputStream(file);
						RandomAccessFile file=new RandomAccessFile("/sdcard/"+threadId+".txt","rwd");//记录当前线程下载的长度
						raf.write(buff, 0, len);
						total+=len;
						//System.out.println("线程"+threadId+"   下载长度:"+total);
						file.write((""+(total+startIndex)).getBytes());
						file.close();
						//更新进度条
						synchronized (MainActivity.this) {
							currentProcess+=len;//获取所有线程下载的总进度
							pb.setProgress(currentProcess);//更改进度条的进度

							Message msg=Message.obtain();//复用旧的消息
							msg.what=UPDATE_TEXT;
							handler.sendMessage(msg);
						}

					}
					is.close();
					raf.close();
					System.out.println("线程"+threadId+"下载完毕...");

				}else{
					System.out.println("线程"+threadId+"下载失败...");
				}

				/*File deleteFile=new File(threadId+".txt");
				deleteFile.delete();*/

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

		private synchronized void threadFinish() {
			//这部分的作用:防止某一个记录文件在资源下载完后没有被删除
			runingThread--;
			if(runingThread==0){
				for(int i=1;i<=3;i++){
					File file=new File("/sdcard/"+i+".txt");
					file.delete();
				}
				System.out.println("资源已经下载完毕,删除所有的下载记录...");
				Message msg=new Message();
				msg.what=DOWN_LOAD_FINISH;
				handler.sendMessage(msg);
			}
		}
	}

}

运行的效果图:

在下载的过程中,退出程序,然后在打开程序,程序会接着在原来的基础上继续下载。

最后打开File Explor中的sdcard,就会发现下载的文件:

源代码的下载地址:http://download.csdn.net/detail/dangnianmingyue_gg/9026189

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-28 13:41:23

android----断点多线程下载的相关文章

Android中多线程下载列表的封装实现(含进度反馈)

来源:http://blog.csdn.net/u011638883/article/details/17347015 实现了一下Android中的文件多线程下载模块,支持自定义线程数.断点续传.下载任务的删除,添加等功能,这里封装了一下,功能已全部实现.不过由于使用的是最简单的手动线程数组及消息通知实现,可能还存在某些小问题.笔者会在后面的使用过程中再进行优化完善.先看一下程序测试效果,这里指定了5个下载任务,以及2个下载线程,具体如下: 要运行以上Demo需要自己搭建服务器,和简单,只需要把

Android之——多线程下载示例(一)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46883927 一.概述 说到Android中的文件下载,Android API中明确要求将耗时的操作放到一个子线程中执行,文件的下载无疑是需要耗费时间的,所以要将文件的下载放到子线程中执行.下面,我们一起来实现一个Android中利用多线程下载文件的小例子. 二.服务端准备 在这个小例子中我以下载有道词典为例,在网上下载有道词典的安装包,在eclipse中新建项目web,将下载的

Android版多线程下载器核心代码分享

首先给大家分享多线程下载核心类: 1 package com.example.urltest; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.RandomAccessFile; 6 import java.net.HttpURLConnection; 7 import java.net.MalformedURLException; 8 import java.net.URL; 9 im

Android 之多线程下载原理

在Android之中呢,对于多线程的操作很是平凡,所以对于多线程的理解越深,那么对于自己的程序便能够很好的运行 这也是对于Android开发是一个重要的知识点,那么我们现在来了解多线程的下载原理. android 多线程下载 多线程下载步骤: 1.本地创建一个跟服务器一样的大小一样的文件 临时文件. 2.计算分配几个线程去下载服务器上的资源 每个文件下载的位置. 3.开启线程,每一个线程下载对应的文件. 4.如果所有的线程都把自己的数据下载完成了,服务器上的资源就被下载到本地了 如图所示:(假设

Android之——多线程下载演示样例

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46883927 一.概述 说到Android中的文件下载.Android API中明白要求将耗时的操作放到一个子线程中运行,文件的下载无疑是须要耗费时间的.所以要将文件的下载放到子线程中运行. 以下,我们一起来实现一个Android中利用多线程下载文件的小样例. 二.服务端准备 在这个小样例中我下面载有道词典为例.在网上下载有道词典的安装包,在eclipse中新建项目web.将下载

Android 模拟多线程下载

以下是一个多线程下载的例子,见代码: 1.首先是布局文件 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height

Android开发--多线程下载加断点续传

文件下载在App应用中也用到很多,一般版本更新时多要用的文件下载来进行处理,以前也有看过很多大神有过该方面的博客,今天我也自己来实践一下,写的一般,还请大家多提意见,共同进步.主要思路: 1.多线程下载: 首先通过下载总线程数来划分文件的下载区域:利用int range = fileSize / threadCount:得到每一段下载量:每一段的位置是i * range到(i + 1) * rang  - 1,注意最后一段的位置是到filesize - 1: 通过Http协议的Range字段实现

Android中 多线程下载原理

计算每个线程的下载起始终止位置公式如下 文件读写方式4中类型 工程源码目录 package cn.itcast.download; import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MulThreadDownloader { public stat

android开发笔记之多线程下载及断点续传

今天我们来接触一下多线程下载,当然也包括断点续传,我们可以看到 很多下载器,当开通会员的时候下载东西的速度就变得快了许多,这是为什么呢?这就是跟今天讲的多线程有关系了,其实就是多开了几个线程一起下载罢了.当然真正的多线程下载要比这个复杂,要考虑很多问题. 做个不恰当的比喻: 假如我们把一个服务器上的文件看作是一个水缸里的水的话,那么多线程下载就相当于从水缸上打了多个小孔,然后塞进去小管道进行抽水.呵呵,也许这个比喻不够准确. 效果: 这里下载的是本地服务器上的文件,你们可以下载网络上的一些文件.

android程序----&gt;android多线程下载(二)

上篇我们讲到了android中下载的断点续传问题,今天我们开始学习下载的多线程问题.本次的多线程源码下载:androdi中多线程下载的实现代码.有关断点续传的问题,请参见博客:android程序---->android多线程下载(一) 目录导航 android中多线程下载的思路 android中多线程中的原理说明 android中多线程下载的实现 友情链接 android中多线程下载的思路 一. 多线程下载的步骤说明: 第一步: 我们要获得下载资源的的长度,用http请求中HttpURLConn