布局文件
1 -2 - 3 - 84 65 7 9 10 11
MyHandler.java
1 package com.itheima.download; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 8 import org.apache.http.HttpEntity; 9 10 import android.content.Context;11 12 import com.loopj.android.http.FileAsyncHttpResponseHandler;13 14 public abstract class MyFileHandler extends FileAsyncHttpResponseHandler {15 private boolean isCancel;16 17 public MyFileHandler(Context context) {18 super(context);19 }20 21 public MyFileHandler(File file) {22 super(file);23 }24 25 @Override26 protected byte[] getResponseData(HttpEntity entity) throws IOException {27 if (entity != null) {28 InputStream instream = entity.getContent();29 long contentLength = entity.getContentLength();30 FileOutputStream buffer = new FileOutputStream(getTargetFile(), true);31 if (instream != null) {32 try {33 byte[] tmp = new byte[BUFFER_SIZE];34 int l, count = 0;35 // do not send messages if request has been cancelled36 while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {37 if (isCancel)38 break;39 count += l;40 buffer.write(tmp, 0, l);41 sendProgressMessage(count, (int) contentLength);42 }43 } finally {44 instream.close();45 buffer.flush();46 buffer.close();47 }48 }49 }50 return null;51 }52 53 public void cancel() {54 isCancel = true;55 }56 57 }
MainActivity.java
1 package com.itheima.download; 2 3 import java.io.File; 4 5 import android.app.Activity; 6 import android.os.Bundle; 7 import android.os.Environment; 8 import android.view.View; 9 import android.widget.EditText;10 import android.widget.ImageButton;11 import android.widget.ProgressBar;12 import android.widget.TextView;13 14 public class MainActivity extends Activity {15 16 // private AsyncHttpClient client;17 18 private EditText pathET;19 private ProgressBar downloadPB;20 private TextView percentTV;21 private TextView progressTV;22 private DownloadTask task;23 24 @Override25 protected void onCreate(Bundle savedInstanceState) {26 super.onCreate(savedInstanceState);27 setContentView(R.layout.activity_main);28 29 pathET = (EditText) findViewById(R.id.pathET);30 downloadPB = (ProgressBar) findViewById(R.id.downloadPB);31 percentTV = (TextView) findViewById(R.id.percentTV);32 progressTV = (TextView) findViewById(R.id.progressTV);33 34 // client = new AsyncHttpClient();35 }36 37 public void download(View v) {38 ImageButton ib = (ImageButton) v;39 40 if (task == null) {41 String targetUrl = pathET.getText().toString().trim();42 File localFile = new File(Environment.getExternalStorageDirectory(), targetUrl.substring(targetUrl.lastIndexOf("/") + 1));43 task = new DownloadTask(targetUrl, localFile, 3, this, downloadPB, percentTV, progressTV);44 task.execute();45 ib.setImageResource(android.R.drawable.ic_media_pause);46 } else {47 task.stop();48 task = null;49 ib.setImageResource(android.R.drawable.ic_media_play);50 }51 }52 53 /*54 public void classicDownload(View v) {55 String path = pathET.getText().toString().trim();56 File file = new File("/mnt/sdcard/", path.substring(path.lastIndexOf("/") + 1));57 58 client.get(path, new FileAsyncHttpResponseHandler(file) { // 处理文件传输的处理器59 public void onSuccess(int statusCode, Header[] headers, File file) {60 Toast.makeText(getApplicationContext(), "下载成功", Toast.LENGTH_SHORT).show();61 }62 public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {63 Toast.makeText(getApplicationContext(), "下载失败 " + statusCode, Toast.LENGTH_SHORT).show();64 throwable.printStackTrace();65 }66 public void onProgress(int bytesWritten, int totalSize) { // 下载或上传的进度67 System.out.println(bytesWritten + " / " + totalSize + " (" + bytesWritten * 100 / totalSize + "%)");68 }69 });70 }71 */72 73 }
DownloadTask.java
1 package com.itheima.download; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.util.ArrayList; 8 9 import org.apache.http.Header; 10 11 import android.content.Context; 12 import android.widget.ProgressBar; 13 import android.widget.TextView; 14 15 import com.loopj.android.http.AsyncHttpClient; 16 import com.loopj.android.http.AsyncHttpResponseHandler; 17 18 public class DownloadTask { 19 private String targetUrl; 20 private File localFile; 21 private int threadAmount; 22 private Context context; 23 private ProgressBar downloadPB; 24 private TextView percentTV; 25 private TextView progressTV; 26 27 private long contentLength; 28 private long threadLength; 29 private ArrayListcacheList = new ArrayList (); 30 private ArrayList handlerList = new ArrayList (); 31 32 /** 33 * 创建下载任务 34 * @param targetUrl 目标地址 35 * @param localFile 本地路径 36 * @param threadAmount 线程数量 37 * @param context 应用环境 38 * @param downloadPB 39 * @param progressTV 40 * @param percentTV 41 */ 42 public DownloadTask(String targetUrl, File localFile, int threadAmount, Context context, ProgressBar downloadPB, TextView percentTV, TextView progressTV) { 43 super(); 44 this.targetUrl = targetUrl; 45 this.localFile = localFile; 46 this.threadAmount = threadAmount; 47 this.context = context; 48 this.downloadPB = downloadPB; 49 this.percentTV = percentTV; 50 this.progressTV = progressTV; 51 } 52 53 public void execute() { 54 new AsyncHttpClient().head(targetUrl, new AsyncHttpResponseHandler() { // 根据URL向服务器发起一个请求, 获取响应头 55 public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { 56 caculateLength(headers); // 获取文件总长度, 计算每个线程负责的长度 57 beginDownload(); // 开启多个线程下载 58 } 59 public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { 60 } 61 }); 62 } 63 64 private void caculateLength(Header[] headers) { 65 for (Header header : headers) 66 if ("Content-Length".equals(header.getName())) 67 contentLength = Long.parseLong(header.getValue()); // 从相应头中获取文件总大小 68 threadLength = (contentLength + threadAmount - 1) / threadAmount; // 计算每个线程负责多少 69 downloadPB.setMax((int) contentLength); // 设置进度条的最大刻度为文件总大小 70 } 71 72 private void beginDownload() { 73 for (int i = 0; i < threadAmount; i++) { // 定义循环, 每次循环启动1个线程下载 74 File cacheFile = new File(context.getCacheDir(), localFile.getName() + ".temp" + i); // 定义临时文件的路径 75 cacheList.add(cacheFile); // 把文件装入集合 76 77 long begin = i * threadLength + cacheFile.length(); // 计算开始位置 78 long end = i * threadLength + threadLength - 1; // 计算结束位置 79 System.out.println(i + ": " + begin + " - " + end); 80 if (begin > end) 81 continue; 82 83 MyFileHandler fileHandler = new MyFileHandler(cacheFile) { // 发送请求, 下载数据, 存储到临时文件 84 private long ms; 85 public void onSuccess(int statusCode, Header[] headers, File file) { 86 System.out.println(Thread.currentThread().getName() + ": " + file + " 下载完成"); 87 checkOtherThread(); // 检查其他线程是否下载完毕, 如果都完了, 合并文件 88 } 89 public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) { 90 } 91 public void onProgress(int bytesWritten, int totalSize) { // 运行频率非常高 92 if (System.currentTimeMillis() - ms > 100) { 93 ms = System.currentTimeMillis(); 94 updateProgress(); 95 } 96 } 97 }; 98 handlerList.add(fileHandler); 99 100 AsyncHttpClient client = new AsyncHttpClient();101 client.addHeader("Range", "bytes=" + begin + "-" + end); // 设置请求数据的范围102 client.get(targetUrl, fileHandler);103 }104 }105 106 private void updateProgress() {107 long finishLength = getFinishLength();108 if (finishLength == 0)109 return;110 downloadPB.setProgress((int) finishLength);111 percentTV.setText(finishLength * 1000 / contentLength / 10f + "%"); 112 progressTV.setText(finishLength + "/" + contentLength);113 }114 115 private long getFinishLength() {116 long finishLength = 0;117 for (File cacheFile : cacheList) // 遍历所有临时文件118 finishLength += cacheFile.length(); // 统计总长度119 return finishLength;120 }121 122 private void checkOtherThread() {123 if (getFinishLength() == contentLength) { // 如果文件长度和ContentLength相等, 代表下载完成124 updateProgress();125 merge(); // 合并所有的临时文件126 }127 }128 129 private void merge() {130 try {131 FileOutputStream out = new FileOutputStream(localFile); 132 for (File cacheFile : cacheList) { // 遍历所有临时文件133 FileInputStream in = new FileInputStream(cacheFile); 134 byte[] buffer = new byte[8192];135 int length;136 while ((length = in.read(buffer)) != -1) // 读取每个文件137 out.write(buffer, 0, length); // 把每个文件的数据都写出到localFile138 in.close();139 cacheFile.delete();140 }141 out.close();142 } catch (IOException e) {143 throw new RuntimeException(e);144 }145 }146 147 public void stop() {148 for (MyFileHandler fileHandler : handlerList) {149 fileHandler.cancel();150 }151 }152 }