首页 > 代码库 > 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版多线程下载器核心代码分享
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。