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,点击下载弹出对话框,输入路径和文件名 点击确定开始下载

Android版多线程下载器核心代码分享

Android版多线程下载器核心代码分享

你可能感兴趣的:(android)