首页 > 代码库 > Android版多线程下载器核心代码分享

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         @Override170         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                         @Override125                         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                                 @Override136                                 public void run() {137                                     try {138                                         downUtil.download(path, name);139                                     } catch (IOException e) {140                                         // TODO Auto-generated catch block141                                         e.printStackTrace();142                                     }143 144                                     final Timer timer = new Timer();145                                     TimerTask task = new TimerTask() {146 147                                         @Override148                                         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         <LinearLayout13             android:layout_width="match_parent"14             android:layout_height="match_parent"15             android:orientation="vertical" >16 17             <TextView18                 android:layout_width="match_parent"19                 android:layout_height="wrap_content"20                 android:text="要下载的资源的URL:" />21 22             <EditText23                 android:id="@+id/url"24                 android:layout_width="match_parent"25                 android:layout_height="wrap_content"26                 android:text="在在这里输入URL" />27 28             <Button29                 android:id="@+id/down"30                 android:layout_width="match_parent"31                 android:layout_height="wrap_content"32                 android:text="下载" />33             <!-- 定义一个水平进度条,用于显示下载进度 -->34 35             <ProgressBar36                 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     <EditText14         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     <TextView23         android:id="@+id/textView2"24         android:layout_width="wrap_content"25         android:layout_height="wrap_content"26         android:text="文件名:" />27 28     <EditText29         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     <TextView36         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版多线程下载器核心代码分享