mex 发表于 2015-07-02 09:23

Android 实现网络多线程APK文件下载

(转自:http://blog.csdn.net/mad1989/article/details/38421465)
实现原理

(1)首先获得下载文件的长度,然后设置本地文件的长度。

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:

例如10M大小,使用3个线程来下载,

线程下载的数据长度   (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?


之前练习时的一个demo,不多说了,直接上代码吧,有关断点续传,需要使用数据库,不再加了,网上有很多成熟的项目可以直接用。

实例

MainApp: package com.amos.app;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.net.URLConnection;
8 import com.amos.download.R;
9 import android.annotation.SuppressLint;
10 import android.app.Activity;
11 import android.os.Bundle;
12 import android.os.Environment;
13 import android.os.Handler;
14 import android.os.Message;
15 import android.util.Log;
16 import android.view.View;
17 import android.view.View.OnClickListener;
18 import android.widget.ProgressBar;
19 import android.widget.TextView;
20 import android.widget.Toast;
21
22 /**
23* @author yangxiaolong
24* @2014-5-6
25*/
26 public class MainApp extends Activity implements OnClickListener {
27
28   private static final String TAG = MainApp.class.getSimpleName();
29
30   /** 显示下载进度TextView */
31   private TextView mMessageView;
32   /** 显示下载进度ProgressBar */
33   private ProgressBar mProgressbar;
34
35   @Override
36   protected void onCreate(Bundle savedInstanceState) {
37         super.onCreate(savedInstanceState);
38         setContentView(R.layout.progress_activity);
39         findViewById(R.id.download_btn).setOnClickListener(this);
40         mMessageView = (TextView) findViewById(R.id.download_message);
41         mProgressbar = (ProgressBar) findViewById(R.id.download_progress);
42   }
43
44   @Override
45   public void onClick(View v) {
46         if (v.getId() == R.id.download_btn) {
47             doDownload();
48         }
49   }
50
51   /**
52      * 使用Handler更新UI界面信息
53      */
54   @SuppressLint("HandlerLeak")
55   Handler mHandler = new Handler() {
56         @Override
57         public void handleMessage(Message msg) {
58
59             mProgressbar.setProgress(msg.getData().getInt("size"));
60
61             float temp = (float) mProgressbar.getProgress()
62                     / (float) mProgressbar.getMax();
63
64             int progress = (int) (temp * 100);
65             if (progress == 100) {
66               Toast.makeText(MainApp.this, "下载完成!", Toast.LENGTH_LONG).show();
67             }
68             mMessageView.setText("下载进度:" + progress + " %");
69
70         }
71   };
72
73   /**
74      * 下载准备工作,获取SD卡路径、开启线程
75      */
76   private void doDownload() {
77         // 获取SD卡路径
78         String path = Environment.getExternalStorageDirectory()
79               + "/amosdownload/";
80         File file = new File(path);
81         // 如果SD卡目录不存在创建
82         if (!file.exists()) {
83             file.mkdir();
84         }
85         // 设置progressBar初始化
86         mProgressbar.setProgress(0);
87
88         // 简单起见,我先把URL和文件名称写死,其实这些都可以通过HttpHeader获取到
89         String downloadUrl = "http://gdown.baidu.com/data/wisegame/91319a5a1dfae322/baidu_16785426.apk";
90         String fileName = "baidu_16785426.apk";
91         int threadNum = 5;
92         String filepath = path + fileName;
93         Log.d(TAG, "download filepath:" + filepath);
94         downloadTask task = new downloadTask(downloadUrl, threadNum, filepath);
95         task.start();
96   }
97
98   /**
99      * 多线程文件下载
100      *
101      * @author yangxiaolong
102      * @2014-8-7
103      */
104   class downloadTask extends Thread {
105         private String downloadUrl;// 下载链接地址
106         private int threadNum;// 开启的线程数
107         private String filePath;// 保存文件路径地址
108         private int blockSize;// 每一个线程的下载量
109
110         public downloadTask(String downloadUrl, int threadNum, String fileptah) {
111             this.downloadUrl = downloadUrl;
112             this.threadNum = threadNum;
113             this.filePath = fileptah;
114         }
115
116         @Override
117         public void run() {
118
119             FileDownloadThread[] threads = new FileDownloadThread;
120             try {
121               URL url = new URL(downloadUrl);
122               Log.d(TAG, "download file http path:" + downloadUrl);
123               URLConnection conn = url.openConnection();
124               // 读取下载文件总大小
125               int fileSize = conn.getContentLength();
126               if (fileSize <= 0) {
127                     System.out.println("读取文件失败");
128                     return;
129               }
130               // 设置ProgressBar最大的长度为文件Size
131               mProgressbar.setMax(fileSize);
132
133               // 计算每条线程下载的数据长度
134               blockSize = (fileSize % threadNum) == 0 ? fileSize / threadNum
135                         : fileSize / threadNum + 1;
136
137               Log.d(TAG, "fileSize:" + fileSize + "blockSize:");
138
139               File file = new File(filePath);
140               for (int i = 0; i < threads.length; i++) {
141                     // 启动线程,分别下载每个线程需要下载的部分
142                     threads = new FileDownloadThread(url, file, blockSize,
143                           (i + 1));
144                     threads.setName("Thread:" + i);
145                     threads.start();
146               }
147
148               boolean isfinished = false;
149               int downloadedAllSize = 0;
150               while (!isfinished) {
151                     isfinished = true;
152                     // 当前所有线程下载总量
153                     downloadedAllSize = 0;
154                     for (int i = 0; i < threads.length; i++) {
155                         downloadedAllSize += threads.getDownloadLength();
156                         if (!threads.isCompleted()) {
157                           isfinished = false;
158                         }
159                     }
160                     // 通知handler去更新视图组件
161                     Message msg = new Message();
162                     msg.getData().putInt("size", downloadedAllSize);
163                     mHandler.sendMessage(msg);
164                     // Log.d(TAG, "current downloadSize:" + downloadedAllSize);
165                     Thread.sleep(1000);// 休息1秒后再读取下载进度
166               }
167               Log.d(TAG, " all of downloadSize:" + downloadedAllSize);
168
169             } catch (MalformedURLException e) {
170               e.printStackTrace();
171             } catch (IOException e) {
172               e.printStackTrace();
173             } catch (InterruptedException e) {
174               e.printStackTrace();
175             }
176
177         }
178   }
179
180 }FileDownloadThread:package com.amos.app;
2
3 import java.io.BufferedInputStream;
4 import java.io.File;
5 import java.io.IOException;
6 import java.io.RandomAccessFile;
7 import java.net.URL;
8 import java.net.URLConnection;
9 import android.util.Log;
10
11 /**
12* 文件下载类
13*
14* @author yangxiaolong
15* @2014-5-6
16*/
17 public class FileDownloadThread extends Thread {
18
19   private static final String TAG = FileDownloadThread.class.getSimpleName();
20
21   /** 当前下载是否完成 */
22   private boolean isCompleted = false;
23   /** 当前下载文件长度 */
24   private int downloadLength = 0;
25   /** 文件保存路径 */
26   private File file;
27   /** 文件下载路径 */
28   private URL downloadUrl;
29   /** 当前下载线程ID */
30   private int threadId;
31   /** 线程下载数据长度 */
32   private int blockSize;
33
34   /**
35      *
36      * @param url:文件下载地址
37      * @param file:文件保存路径
38      * @param blocksize:下载数据长度
39      * @param threadId:线程ID
40      */
41   public FileDownloadThread(URL downloadUrl, File file, int blocksize,
42             int threadId) {
43         this.downloadUrl = downloadUrl;
44         this.file = file;
45         this.threadId = threadId;
46         this.blockSize = blocksize;
47   }
48
49   @Override
50   public void run() {
51
52         BufferedInputStream bis = null;
53         RandomAccessFile raf = null;
54
55         try {
56             URLConnection conn = downloadUrl.openConnection();
57             conn.setAllowUserInteraction(true);
58
59             int startPos = blockSize * (threadId - 1);//开始位置
60             int endPos = blockSize * threadId - 1;//结束位置
61             //设置当前线程下载的起点、终点
62             conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
63             System.out.println(Thread.currentThread().getName() + "bytes="
64                     + startPos + "-" + endPos);
65
66             byte[] buffer = new byte;
67             bis = new BufferedInputStream(conn.getInputStream());
68
69             raf = new RandomAccessFile(file, "rwd");
70             raf.seek(startPos);
71             int len;
72             while ((len = bis.read(buffer, 0, 1024)) != -1) {
73               raf.write(buffer, 0, len);
74               downloadLength += len;
75             }
76             isCompleted = true;
77             Log.d(TAG, "current thread task has finished,all size:"
78                     + downloadLength);
79
80         } catch (IOException e) {
81             e.printStackTrace();
82         } finally {
83             if (bis != null) {
84               try {
85                     bis.close();
86               } catch (IOException e) {
87                     e.printStackTrace();
88               }
89             }
90             if (raf != null) {
91               try {
92                     raf.close();
93               } catch (IOException e) {
94                     e.printStackTrace();
95               }
96             }
97         }
98   }
99
100   /**
101      * 线程文件是否下载完毕
102      */
103   public boolean isCompleted() {
104         return isCompleted;
105   }
106
107   /**
108      * 线程下载文件长度
109      */
110   public int getDownloadLength() {
111         return downloadLength;
112   }
113
114 }补充:.xml文件: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="match_parent"
5   android:background="@android:color/white"
6   android:orientation="vertical" >
7
8   <Button
9         android:id="@+id/download_btn"
10         android:layout_width="match_parent"
11         android:layout_height="60dp"
12         android:layout_gravity="center"
13         android:layout_marginLeft="10dp"
14         android:layout_marginRight="10dp"
15         android:layout_marginTop="50dp"
16         android:text="Download"
17         android:textSize="18sp" />
18
19   <ProgressBar
20         android:id="@+id/download_progress"
21         style="?android:attr/progressBarStyleHorizontal"
22         android:layout_width="fill_parent"
23         android:layout_height="wrap_content"
24         android:layout_marginLeft="10dip"
25         android:layout_marginRight="10dip"
26         android:layout_marginTop="20dp"
27         android:indeterminate="false"
28         android:max="100" />
29
30   <TextView
31         android:id="@+id/download_message"
32         android:layout_width="wrap_content"
33         android:layout_height="wrap_content"
34         android:layout_gravity="center"
35         android:layout_marginTop="10dp"
36         android:maxLines="1"
37         android:text="50%"
38         android:textSize="18dip" />
39
40 </LinearLayout>效果图:
页: [1]
查看完整版本: Android 实现网络多线程APK文件下载