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 import java.net.URLDecoder;
 10 
 11 public class DownUtil {
 12     private String urlPath;
 13     private String defaultTargetPath;
 14     private int threadNum;
 15     private DownThread[] threads;
 16     private int fileSize = -100;
 17     private String fileName = "未知文件";
 18     private boolean isGetFileInformation = false;
 19 
 20     public DownUtil(String urlPath, int threadNum) {
 21         this.urlPath = urlPath;
 22         this.defaultTargetPath = "/mnt/sdcard/";
 23         this.threadNum = threadNum;
 24         this.threads = new DownThread[threadNum];
 25     }
 26 
 27     private HttpURLConnection connection() throws IOException {
 28 
 29         URL url = new URL(urlPath);
 30         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 31         connection.setConnectTimeout(5 * 1000);
 32         connection.setRequestMethod("GET");
 33         connection.setRequestProperty(
 34                 "Accept",
 35                 "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
 36                         + "application/x-shockwave-flash, application/xaml+xml, "
 37                         + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
 38                         + "application/x-ms-application, application/vnd.ms-excel, "
 39                         + "application/vnd.ms-powerpoint, application/msword, */*");
 40         connection.setRequestProperty("Accept-Language", "zh-CN");
 41         connection.setRequestProperty("Charset", "UTF-8");
 42         connection.setRequestProperty("Connection", "Keep-Alive");
 43 
 44         return connection;
 45     }
 46 
 47     public void getFileInformation() throws IOException {
 48 
 49         HttpURLConnection connection = connection();
 50 
 51         connection.setInstanceFollowRedirects(false);
 52 
 53         int status = connection.getResponseCode();
 54         if (status != -1) {
 55 
 56             if (status / 100 == 3) {// 当响应码是302时,说明可以获得重定向的资源地址
 57                 // 得到文件名(此方法不能正确的获取所有url的资源文件名)
 58                 String name = connection.getHeaderField("Location");
 59                 name = URLDecoder.decode(name.substring(name.lastIndexOf(‘/‘)), "UTF-8");
 60                 this.fileName = name;
 61             }
 62 
 63             // 得到文件大小
 64             this.fileSize = connection.getContentLength();
 65             if (fileSize <= 0) {
 66                 isGetFileInformation = false;
 67             } else {
 68                 isGetFileInformation = true;
 69             }
 70             connection.disconnect();
 71 
 72         } else {
 73 
 74             connection.disconnect();
 75             isGetFileInformation = false;
 76 
 77         }
 78 
 79     }
 80 
 81     public boolean download(String targetPath, String fileName) throws IOException {
 82 
 83         if (isGetFileInformation == false) {
 84             getFileInformation();
 85         }
 86 
 87         if (isGetFileInformation) {
 88 
 89             String absFilePath = targetPath + fileName;
 90 
 91             int currentPartSize = (fileSize / threadNum) + 1;// 每一部分需要下载的大小,注意此处加1是为了避免不能整除带来的误差
 92             RandomAccessFile file = new RandomAccessFile(absFilePath, "rw");
 93             file.setLength(fileSize);
 94             file.close();
 95             for (int i = 0; i < threadNum; i++) {
 96                 int startPos = i * currentPartSize;
 97                 RandomAccessFile currentPart = new RandomAccessFile(absFilePath, "rw");// 打开目标文件
 98                 currentPart.seek(startPos);
 99                 threads[i] = new DownThread(startPos, currentPartSize, currentPart);
100                 threads[i].start();
101 
102             }
103 
104             return true;
105         } else {
106             return false;
107 
108         }
109     }
110 
111     public boolean download() throws IOException {
112         if (isGetFileInformation) {
113 
114             return download(this.defaultTargetPath, this.getFileName());
115 
116         } else {
117             getFileInformation();
118             return download(this.defaultTargetPath, this.getFileName());
119 
120         }
121 
122     }
123 
124     public double getCompleteRate() {
125 
126         int sumSize = 0;
127         for (int i = 0; i < threadNum; i++) {
128 
129             sumSize += threads[i].length;
130         }
131 
132         return sumSize * 1.0 / fileSize;
133 
134     }
135 
136     public String getDefaultTargetPath() {
137         return defaultTargetPath;
138     }
139 
140     public int getFileSize() {
141         return fileSize;
142     }
143 
144     public String getFileName() {
145         return fileName;
146     }
147 
148     public void setFileName(String fileName) {
149         this.fileName = fileName;
150     }
151 
152     public boolean isGetFileInformation() {
153         return isGetFileInformation;
154     }
155 
156     private class DownThread extends Thread {
157         private int startPos;
158         private int currentPartSize;
159         private RandomAccessFile currentPart;
160         int length; // 该线程已经下载的字节数
161 
162         public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) {
163 
164             this.startPos = startPos;
165             this.currentPartSize = currentPartSize;
166             this.currentPart = currentPart;
167         }
168 
169         @Override
170         public void run() {
171 
172             try {
173 
174                 HttpURLConnection connection = connection();
175                 int endPos = startPos + currentPartSize;
176                 connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);// 使用http来设置一个文件的下载范围(startPos-endPos)
177                 InputStream inStream = connection.getInputStream();
178                 // inStream.skip(startPos); // skip函数有时候不起作用
179                 byte[] buffer = new byte[1024];
180                 int hasRead = 0;
181                 while (length < currentPartSize && (hasRead = inStream.read(buffer)) > 0) {
182 
183                     currentPart.write(buffer, 0, hasRead);
184                     length = length + hasRead;
185 
186                 }
187 
188                 inStream.close();
189                 currentPart.close();
190                 connection.disconnect();
191 
192             } catch (MalformedURLException e2) {
193                 e2.printStackTrace();
194             } catch (IOException e) {
195                 e.printStackTrace();
196             }
197 
198         }
199 
200     }
201 
202 }

下面是界面的逻辑代码:

  1 package com.example.urltest;
  2 
  3 import android.app.Activity;
  4 import android.app.AlertDialog;
  5 import android.app.ProgressDialog;
  6 import android.content.DialogInterface;
  7 import android.os.Bundle;
  8 import android.os.Message;
  9 import android.view.View;
 10 import android.view.View.OnClickListener;
 11 import android.widget.Button;
 12 import android.widget.EditText;
 13 import android.widget.ProgressBar;
 14 import android.widget.TextView;
 15 import android.widget.Toast;
 16 
 17 import java.io.IOException;
 18 import java.util.Timer;
 19 import java.util.TimerTask;
 20 
 21 public class MultiThreadDown extends Activity {
 22     EditText url, target;
 23     Button downButton;
 24     ProgressBar bar;
 25     ProgressDialog progressDialog;
 26     View downView;
 27     DownUtil downUtil;
 28     private int mDownStatus;
 29     private int threadNum = 6; // 默认的线程数
 30     android.os.Handler handler = new android.os.Handler() {
 31 
 32         @Override
 33         public void handleMessage(Message msg) {
 34             if (msg.what == 0x123) {
 35                 bar.setProgress(mDownStatus);
 36                 if (mDownStatus >= 100) {
 37                     Toast.makeText(MultiThreadDown.this, "下载完成", Toast.LENGTH_SHORT).show();
 38                 }
 39                 // Log.i("csx", "" + mDownStatus);
 40 
 41             }
 42         }
 43 
 44     };
 45 
 46     @Override
 47     protected void onCreate(Bundle savedInstanceState) {
 48 
 49         super.onCreate(savedInstanceState);
 50         setContentView(R.layout.layout_down);
 51         url = (EditText) findViewById(R.id.url);
 52 
 53         downButton = (Button) findViewById(R.id.down);
 54         bar = (ProgressBar) findViewById(R.id.bar);
 55         progressDialog = new ProgressDialog(this);
 56         progressDialog.setTitle("尝试连接");
 57         progressDialog.setMessage("正在连接...");
 58         downButton.setOnClickListener(new DownButtonOnClickListener());
 59 
 60     }
 61 
 62     private class DownButtonOnClickListener implements OnClickListener {
 63 
 64         EditText targetFilePath, fileName;
 65         TextView fileSize;
 66         Thread connectionThread;
 67 
 68         public Thread instanceOfConnectionThread() {
 69             return new Thread() {
 70 
 71                 @Override
 72                 public void run() {
 73                     try {
 74                         downUtil.getFileInformation();
 75 
 76                     } catch (IOException e1) {
 77                         e1.printStackTrace();
 78                     }
 79 
 80                 }
 81 
 82             };
 83         }
 84 
 85         @Override
 86         public void onClick(View v) {
 87 
 88             String urlPath = url.getText().toString();
 89             if (urlPath == null || urlPath.equals("")) {
 90                 return;
 91             }
 92             progressDialog.show();
 93             downUtil = new DownUtil(urlPath, threadNum);
 94             connectionThread = instanceOfConnectionThread();
 95             connectionThread.start();
 96 
 97             int connectionNum = 3;
 98             while (!downUtil.isGetFileInformation() && connectionNum > 0) {// 循环请求连接,如果3次之后还没有连接成功,就退出
 99                 if (!connectionThread.isAlive()) {
100                     connectionThread = null;
101                     connectionThread = instanceOfConnectionThread();
102                     connectionThread.start();
103                     connectionNum--;
104                 }
105 
106             }
107 
108             progressDialog.cancel();
109             if (!downUtil.isGetFileInformation()) {
110                 Toast.makeText(MultiThreadDown.this, "请求失败!", Toast.LENGTH_SHORT).show();
111                 return;
112             }
113             downView = getLayoutInflater().inflate(R.layout.layout_download_view, null);
114             targetFilePath = (EditText) downView.findViewById(R.id.editText_target_path);
115             fileName = (EditText) downView.findViewById(R.id.editText_file_name);
116             fileSize = (TextView) downView.findViewById(R.id.textView_file_size);
117             targetFilePath.setText(downUtil.getDefaultTargetPath());
118             fileName.setText(downUtil.getFileName());
119             fileSize.append("" + ((double) downUtil.getFileSize()) / 1024 + "k");
120 
121             new AlertDialog.Builder(MultiThreadDown.this).setView(downView)
122                     .setPositiveButton("确定", new DialogInterface.OnClickListener() {
123 
124                         @Override
125                         public void onClick(DialogInterface dialog, int which) {
126                             if (!downUtil.isGetFileInformation()) {
127                                 dialog.dismiss();
128                                 return;
129                             }
130                             final String path = targetFilePath.getText().toString();
131                             final String name = fileName.getText().toString();
132 
133                             new Thread() {
134 
135                                 @Override
136                                 public void run() {
137                                     try {
138                                         downUtil.download(path, name);
139                                     } catch (IOException e) {
140                                         // TODO Auto-generated catch block
141                                         e.printStackTrace();
142                                     }
143 
144                                     final Timer timer = new Timer();
145                                     TimerTask task = new TimerTask() {
146 
147                                         @Override
148                                         public void run() {
149 
150                                             mDownStatus = (int) (downUtil.getCompleteRate() * 100);
151                                             handler.sendEmptyMessage(0x123);
152                                             if (mDownStatus >= 100) {
153                                                 timer.cancel();
154                                             }
155 
156                                         }
157                                     };
158                                     timer.schedule(task, 0, 100);
159 
160                                 }
161 
162                             }.start();
163 
164                         }
165                     }).setNegativeButton("取消", null)
166                     .setTitle(downUtil.isGetFileInformation() ? "链接可用" : "链接不可用").show();
167 
168         }
169     }
170 
171 }

下面是主页面布局:layout_down.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:orientation="vertical" >
 6 
 7     <ScrollView
 8         android:id="@+id/scrollView1"
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content" >
11 
12         <LinearLayout
13             android:layout_width="match_parent"
14             android:layout_height="match_parent"
15             android:orientation="vertical" >
16 
17             <TextView
18                 android:layout_width="match_parent"
19                 android:layout_height="wrap_content"
20                 android:text="要下载的资源的URL:" />
21 
22             <EditText
23                 android:id="@+id/url"
24                 android:layout_width="match_parent"
25                 android:layout_height="wrap_content"
26                 android:text="在在这里输入URL" />
27 
28             <Button
29                 android:id="@+id/down"
30                 android:layout_width="match_parent"
31                 android:layout_height="wrap_content"
32                 android:text="下载" />
33             <!-- 定义一个水平进度条,用于显示下载进度 -->
34 
35             <ProgressBar
36                 android:id="@+id/bar"
37                 style="?android:attr/progressBarStyleHorizontal"
38                 android:layout_width="match_parent"
39                 android:layout_height="wrap_content"
40                 android:max="100" />
41         </LinearLayout>
42     </ScrollView>
43 
44 </LinearLayout>

下面是下载选项dialog布局:layout_download_view.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:orientation="vertical" >
 6 
 7     <TextView
 8         android:id="@+id/textView1"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="下载路径:" />
12 
13     <EditText
14         android:id="@+id/editText_target_path"
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content"
17         android:ems="10" >
18 
19         <requestFocus />
20     </EditText>
21 
22     <TextView
23         android:id="@+id/textView2"
24         android:layout_width="wrap_content"
25         android:layout_height="wrap_content"
26         android:text="文件名:" />
27 
28     <EditText
29         android:id="@+id/editText_file_name"
30         android:layout_width="match_parent"
31         android:layout_height="wrap_content"
32         android:maxLines="1"
33         android:ems="10" />
34 
35     <TextView
36         android:id="@+id/textView_file_size"
37         android:layout_width="wrap_content"
38         android:layout_height="wrap_content"
39         android:text="文件大小:" />
40 
41 </LinearLayout>

效果图如下:输入URL,点击下载弹出对话框,输入路径和文件名 点击确定开始下载

技术分享

技术分享

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。