<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/path"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/path"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
/>
</LinearLayout>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
package com.example.dowload;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import android.os.Bundle;
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 {
private EditText path = null;
private static Button start = null;
private static ProgressBar progressBar = null;
private static TextView progress = null;
public static int threadCount = 3;
public static int runningThread = 3;
public static final int DOWNLOAD_ERROR = 1;
public static final int SERVER_ERROR = 2;
public static final int FINISH = 3;
public static final int PUDATE = 4;
public static int length; // 资源总长度
public static int currentProgress = 0;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOAD_ERROR:
Toast.makeText(getApplicationContext(), "下载失败", 1).show();
break;
case SERVER_ERROR:
Toast.makeText(getApplicationContext(), "服务器错误", 1).show();
break;
case FINISH:
Toast.makeText(getApplicationContext(), "下载完成", 1).show();
start.setEnabled(true);
break;
case PUDATE:
progress.setText("下载完成:" + currentProgress * 100 / length + "%"); // 子线程不可修改ui
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取组件
path = (EditText) findViewById(R.id.path);
start = (Button) findViewById(R.id.button1);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
progress = (TextView) findViewById(R.id.progress);
path.setText("http://192.168.1.102:8080/WEB/olay.avi");
start.setOnClickListener(new StartClickListenerImpl());
}
/**
* 下载
*
* @param view
*/
public void download(View view) {
final String urlpath = path.getText().toString();
if (TextUtils.isEmpty(urlpath)) {
Toast.makeText(MainActivity.this, "下载路径错误", 2).show();
}
new Thread() {
public void run() {
try {
// 1 获取服务器,获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件一样大的临时文件
// String
// path="http://192.168.1.102:8080/WEB/olay.avi";//下载路径
// 这里是web项目中的
URL url = new URL(urlpath);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
if (code == 200) {
length = conn.getContentLength();
progressBar.setMax(length);// 设置进度条的最大值
System.out.println("文件总长度" + length);
// 在客户端本地创建一个大小跟服务器端资源一样大小的临时文件
RandomAccessFile raf = new RandomAccessFile(
"/sdcard/olay.avi", "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
endIndex = length;
}
System.out.println("线程:" + threadId + "下载:----"
+ startIndex + "---->" + endIndex);
// 在主线程中调用子线程,开始下载
new DownLoadThread(threadId, startIndex, endIndex,
urlpath).start();
}
} else {
System.out.println("服务器错误");
Message msg = new Message();
msg.what = SERVER_ERROR;
handler.sendMessage(msg);
}
} catch (Exception e) {
Message msg = new Message();
msg.what = DOWNLOAD_ERROR;
handler.sendMessage(msg);
}
}
}.start();
}
/**
* 下载资源的子线程,每个线程下载对应的对应的资源
*
* @author olay
*
*/
public class DownLoadThread extends Thread {
private int threadId, startIndex, endIndex;
private String path;
/**
*
* @param threadId
* 线程id
* @param startIndex
* 线程下载的开始位置
* @param endIndex
* 线程下载的结束位置
* @param path
* 下载路径
*/
public DownLoadThread(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");// 创建仔资源的临时文件
long i = tempFile.length();
if (tempFile.exists() && tempFile.length() > 0) {// 临时文件存在并且不为空
FileInputStream fis = new FileInputStream(tempFile);// 创建文件输入流
byte[] temp = new byte[1024];// 创建缓冲区
int leng = fis.read(temp);// 读取到文件输入流中
String downloadlenLong = new String(temp, 0, leng);
int downloadlenInt = Integer.valueOf(downloadlenLong);
int alreadydownint = downloadlenInt - startIndex;
currentProgress += alreadydownint;// 计算上次断点已经下载的长度
startIndex = downloadlenInt;// 下载后突然断开,第二次下载开始位置为第一次下载完后继续下载
fis.close();
} else {
System.out.println("文件不存在");
}
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
// 重要:请求服务器下载部分的文件 指定文件的下载位置
conn.setRequestProperty("Range", "bytes-" + startIndex + "-"
+ endIndex);
int code = conn.getResponseCode();// 从服务器请求全部资源成功的响应码是200,而从服务器请求部分资源成功的响应码是206
InputStream is = conn.getInputStream();// 返回当前位置对应的文件的输入流
RandomAccessFile raf = new RandomAccessFile("/sdcard/olay.avi",
"rwd");
// 随机写文件的时候从哪个位置开始写
raf.seek(startIndex);// 定位文件
// 写入内存
int len = 0;
byte[] buffer = new byte[1024];// 声明缓冲区
int total = 0; // 已经下载的数据长度
while ((len = is.read(buffer)) != -1) {
raf.write(buffer, 0, len);// 写入到临时文件
total += len;
System.out.println("线程" + threadId + "total:" + total);
RandomAccessFile file = new RandomAccessFile("/sdcard/"
+ threadId + ".txt", "rwd");// 记录当前下载记录的长度
file.write((total + startIndex + "").getBytes());// 帮已经下载的字节写到对应的file文件中
file.close(); // 记得关RandomAccessFile,不然删除不了文件
synchronized (MainActivity.class) {
currentProgress += len; // 获取当前的总进度
// 特殊情况: 进度条对话框可以在子线程里面更改ui,因为内部做了特殊处理
progressBar.setProgress(currentProgress);// 更改界面ProgressBar进度条的进度
// 显示已经下载的比例
// progress.setText("下载完成:"+currentProgress*100/length+"%");
// 子线程不可修改ui
Message msg = Message.obtain(); // 消息池:不用重复new Message
// ,提到效率
msg.what = PUDATE;
handler.sendMessage(msg);
}
}
is.close();
raf.close();
System.out.println("线程" + threadId + "下载完毕...");
} catch (Exception e) {
e.printStackTrace();
} finally {
finish();
}
}
private synchronized void finish() {
runningThread--;
if (runningThread == 0) { // 全部线程下载完成
System.out.println("开始删除记录文件");
for (int i = 1; i <= 3; i++) {
File file = new File("/sdcard/" + i + ".txt");
if (file.exists()) {
if (file.delete()) {
System.out.println("删除" + i + ".txt文件成功");
}
}
}
Message msg = new Message();
msg.what = FINISH;
handler.sendMessage(msg);
}
}
}
private class StartClickListenerImpl implements View.OnClickListener {
@Override
public void onClick(View v) {
start.setEnabled(false);
download(v);
}
}
}