Android多线程下载

一、多线程下载的原理、

      

      将服务端的资源划分给成几个等分的块,分配给不同的线程同时执行下载。

      划分方法 :

                  每个线程分配的长度为:int blocksize = length/n    

                  每个线程的起止位置(i-1)*blocksize--->i*blocksize-1        

                  最后一个线程结束位置为length

二、步骤:

       1、在客户端创建与服务端同等大小的文件,使用RandomAccessFile类远程文件的设置操作

       2.、开启几个线程,分配下载资源

       3.、所有的线程执行完毕之后,文件下载完毕

三、java实现的多线程下载

  1 package com.lewu.download;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileOutputStream;
  6 import java.io.InputStream;
  7 import java.io.RandomAccessFile;
  8 import java.net.HttpURLConnection;
  9 import java.net.URL;
 10 
 11 public class DownloadTest {
 12     public static final String path = "http://192.168.1.118:8080/web/youdao.exe";
 13     public static int threadcount = 0;
 14 
 15     public static void main(String[] args) throws Exception {
 16         // 1.在客户端端创建一个相同大小的文件(获取服务器文件的大小)
 17 
 18         URL url = new URL(path);
 19         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 20         conn.setRequestMethod("GET");
 21         conn.setConnectTimeout(5000);
 22         conn.setRequestProperty(
 23                 "User-Agent",
 24                 "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
 25         int length = conn.getContentLength();
 26         System.err.println("文件的长度为"+length);
 27         File file = new File("youdao.exe");
 28         RandomAccessFile randomfile = new RandomAccessFile(file, "rwd");
 29         randomfile.setLength(length);
 30 
 31         // 创建三个线程 :线程分配下载资源
 32         int blocksize = length / 3;
 33         for (int i = 1; i <=3; i++) {
 34             // 线程执行下载操作 ,需要定位下载的位置,则需要设置一些参数
 35             int beginsize = (i - 1) * blocksize;
 36             int endsize = i * blocksize - 1;
 37             if (i == 3) {
 38                 endsize = length;
 39             }
 40             int id = i;
 41 
 42             // 启动线程
 43             new Thread(new DownloadThread(id, beginsize, endsize)).start();
 44         }
 45 
 46     }
 47 
 48     static class DownloadThread implements Runnable {
 49 
 50         private int id;
 51         private int beginsize;
 52         private int endsize;
 53 
 54         public DownloadThread(int id, int beginsize, int endsize) {
 55             this.id = id;
 56             this.beginsize = beginsize;
 57             this.endsize = endsize;
 58         }
 59 
 60         @Override
 61         public void run() {
 62             try {
 63                 // 每一个线程在创建的时候 都创建一个名为id.text的文件用来保存下载进度
 64                 File idfile = new File("" + id + ".txt");
 65                 if (idfile.exists()) {
 66                     // 将内容即进度读取出来
 67                     FileInputStream fin = new FileInputStream(idfile);
 68                     byte[] result = StreamTools.getBytes(fin);
 69                     String strinfo = new String(result);
 70                     if (!"".equals(strinfo) && strinfo != null) {
 71                         beginsize = Integer.parseInt(strinfo);
 72                     }
 73                 }
 74                 URL url = new URL(DownloadTest.path);
 75                 HttpURLConnection conn = (HttpURLConnection) url
 76                         .openConnection();
 77 
 78                 conn.setRequestMethod("GET");
 79                 conn.setConnectTimeout(5000);
 80                 if (beginsize > endsize) {
 81                     beginsize = endsize - 1;
 82                 }
 83                 conn.setRequestProperty(
 84                         "User-Agent",
 85                         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
 86                 conn.setRequestProperty("Range", "bytes=" + beginsize + "-"
 87                         + endsize);
 88                 System.out.println("线程"+id+"从" + beginsize + "开始下载" + endsize + "结束");
 89 
 90                 File file = new File("youdao.exe");
 91                 RandomAccessFile randomfile = new RandomAccessFile(file, "rwd");
 92                 // 如果下载被强行中断,这保存下载的位置,
 93                 randomfile.seek(beginsize);
 94 
 95                 InputStream in = conn.getInputStream();
 96                 byte[] bt = new byte[1024];
 97 
 98                 int len = 0;
 99                 int total = 0;
100                 while ((len = in.read(bt)) != -1) {
101                     randomfile.write(bt, 0, len);
102                     // 下载量 下载位置
103                     total += len;
104                     // 将位置信息保存到相应的文件
105                     FileOutputStream out = new FileOutputStream(idfile);
106                     out.write((beginsize + total + "").getBytes());
107                     out.flush();
108                     out.close();
109 
110                 }
111                 in.close();
112                 randomfile.close();
113                 System.out.println("线程" + id + "执行完毕!");
114 
115                 // 使用synchronized的代码块保count被多个线程同时访问
116                 synchronized (DownloadTest.class) {
117                     DownloadTest.threadcount++;
118                     if (DownloadTest.threadcount >= 3) {
119                         System.out.println("所有的线程都执行完毕了");
120                         for (int i = 0; i < 3; i++) {
121                             File deleteFile = new File(i + ".txt");
122                             System.out.println(i + "删除" + deleteFile.delete());
123                         }
124                     }
125 
126                 }
127 
128             } catch (Exception e) {
129                 e.printStackTrace();
130             }
131         }
132     }
133 }

 四、移植到Android上

       功能:1、界面上有下载进度条,可以记录下载进度

               2、设置暂停按钮(通过设置flag控制)

  1 package com.lewu.download;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileOutputStream;
  6 import java.io.InputStream;
  7 import java.io.RandomAccessFile;
  8 import java.net.HttpURLConnection;
  9 import java.net.URL;
 10 import android.app.Activity;
 11 import android.os.Bundle;
 12 import android.os.Environment;
 13 import android.view.View;
 14 import android.view.View.OnClickListener;
 15 import android.widget.Button;
 16 import android.widget.EditText;
 17 import android.widget.ProgressBar;
 18 import android.widget.Toast;
 19 
 20 public class MutiDownloadAndActivity extends Activity implements
 21         OnClickListener {
 22     private EditText down_edit;
 23     private Button down_sure;
 24     private Button down_stop;
 25     private ProgressBar bar;
 26     private int totalsize;
 27     private boolean flag=true;
 28     public static int threadcount = 0;
 29 
 30     @Override
 31     public void onCreate(Bundle savedInstanceState) {
 32         super.onCreate(savedInstanceState);
 33         setContentView(R.layout.main);
 34 
 35         down_edit = (EditText) findViewById(R.id.down_edit);
 36         down_sure = (Button) findViewById(R.id.down_sure);
 37         down_stop = (Button) findViewById(R.id.down_stop);
 38         bar = (ProgressBar) findViewById(R.id.progressBar1);
 39 
 40         down_sure.setOnClickListener(this);
 41         down_stop.setOnClickListener(this);
 42 
 43     }
 44 
 45     @Override
 46     public void onClick(View v) {
 47         switch (v.getId()) {
 48         case R.id.down_sure:
 49 
 50             String path = down_edit.getText().toString().trim();
 51             System.out.println(path + ">>>>>>>>>>");
 52             if ("".equals(path)) {
 53                 Toast.makeText(this, "路径不能为空", 0);
 54                 return;
 55             } else {
 56                 down_stop.setClickable(true);
 57                 down_stop.setEnabled(true);
 58                 try {
 59                     URL url = new URL(path);
 60                     HttpURLConnection conn = (HttpURLConnection) url
 61                             .openConnection();
 62                     conn.setRequestMethod("GET");
 63                     conn.setConnectTimeout(5000);
 64                     conn.setRequestProperty(
 65                             "User-Agent",
 66                             "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
 67                     int length = conn.getContentLength();
 68                     System.err.println("文件的长度为" + length);
 69                     //设置进度条的进度
 70                     bar.setMax(length);
 71                     File file = new File(
 72                             Environment.getExternalStorageDirectory(),
 73                             getFileName(path));
 74                     RandomAccessFile randomfile = new RandomAccessFile(file,
 75                             "rwd");
 76                     randomfile.setLength(length);
 77 
 78                     // 创建三个线程 :线程分配下载资源
 79                     int blocksize = length / 3;
 80                     for (int i = 1; i <= 3; i++) {
 81                         // 线程执行下载操作 ,需要定位下载的位置,则需要设置一些参数
 82                         int beginsize = (i - 1) * blocksize;
 83                         int endsize = i * blocksize - 1;
 84                         if (i == 3) {
 85                             endsize = length;
 86                         }
 87                         int id = i;
 88 
 89                         // 启动线程
 90                         new Thread(new DownloadThread(id, beginsize, endsize,
 91                                 path)).start();
 92 
 93                     }
 94                 } catch (Exception e) {
 95                     e.printStackTrace();
 96                 }
 97                 break;
 98             }
 99 
100         case R.id.down_stop:
101             flag = false;
102             down_stop.setClickable(true);
103             down_stop.setEnabled(true);
104 
105             break;
106 
107         }
108     }
109 
110     class DownloadThread implements Runnable {
111 
112         private int id;
113         private int beginsize;
114         private int endsize;
115         private String path;
116 
117         public DownloadThread(int id, int beginsize, int endsize, String path) {
118             this.id = id;
119             this.beginsize = beginsize;
120             this.endsize = endsize;
121             this.path = path;
122         }
123 
124         @Override
125         public void run() {
126             try {
127                 flag = true;
128                 // 每一个线程在创建的时候 都创建一个名为id.text的文件用来保存下载进度
129                 File idfile = new File("/mnt/sdcard/" + id + ".txt");
130                 if (idfile.exists()) {
131                     // 将内容即进度读取出来
132                     FileInputStream fin = new FileInputStream(idfile);
133                     byte[] result = StreamTools.getBytes(fin);
134                     String strinfo = new String(result);
135                     if (!"".equals(strinfo) && strinfo != null) {
136                         beginsize = Integer.parseInt(strinfo);
137                     }
138                 }
139                 URL url = new URL(path);
140                 HttpURLConnection conn = (HttpURLConnection) url
141                         .openConnection();
142 
143                 conn.setRequestMethod("GET");
144                 conn.setConnectTimeout(5000);
145                 if (beginsize > endsize) {
146                     beginsize = endsize - 1;
147                 }
148                 conn.setRequestProperty(
149                         "User-Agent",
150                         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
151                 conn.setRequestProperty("Range", "bytes=" + beginsize + "-"
152                         + endsize);
153                 System.out.println("线程" + id + "从" + beginsize + "开始下载"
154                         + endsize + "结束");
155 
156                 File file = new File(Environment.getExternalStorageDirectory(),
157                         getFileName(path));
158                 RandomAccessFile randomfile = new RandomAccessFile(file, "rwd");
159                 // 如果下载被强行中断,这保存下载的位置,
160                 randomfile.seek(beginsize);
161 
162                 InputStream in = conn.getInputStream();
163                 byte[] bt = new byte[1024];
164 
165                 int len = 0;
166                 int total = 0;
167                 while ((len = in.read(bt)) != -1) {
168                     randomfile.write(bt, 0, len);
169                     // 下载量 下载位置
170                     total += len;
171 
172                     // 设置进度条的进度
173                     setProgressbarProgress(len);
174 
175                     // 将位置信息保存到相应的文件
176                     FileOutputStream out = new FileOutputStream(idfile);
177                     out.write((beginsize + total + "").getBytes());
178                     out.flush();
179                     out.close();
180                     if(!flag){
181                         return;
182                     }
183 
184                 }
185                 in.close();
186                 randomfile.close();
187                 System.out.println("线程" + id + "执行完毕!");
188 
189                 // 使用synchronized的代码块保count被多个线程同时访问
190                 synchronized (MutiDownloadAndActivity.class) {
191                     MutiDownloadAndActivity.threadcount++;
192                     if (MutiDownloadAndActivity.threadcount >= 3) {
193                         System.out.println("所有的线程都执行完毕了");
194                         for (int i = 1; i <= 3; i++) {
195                             File deleteFile = new File("/mnt/sdcard/" + i
196                                     + ".txt");
197                             System.out.println(i + "删除" + deleteFile.delete());
198                         }
199                     }
200 
201                 }
202 
203             } catch (Exception e) {
204                 e.printStackTrace();
205             }
206         }
207     }
208 
209     public static String getFileName(String path) {
210         int index = path.lastIndexOf("/") + 1;
211         return path.substring(index);
212 
213     }
214 
215     public void setProgressbarProgress(int len) {
216         if (len != 0) {
217             totalsize += len;
218             bar.setProgress(totalsize);
219         }
220 
221     }
222 
223 }

      下载界面:

     

原文地址:https://www.cnblogs.com/tagie/p/3074966.html