Android版多线程下载器核心代码分享
首先给大家分享多线程下载核心类:
package com.example.urltest; import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder; public class DownUtil {
private String urlPath;
private String defaultTargetPath;
private int threadNum;
private DownThread[] threads;
private int fileSize = -100;
private String fileName = "未知文件";
private boolean isGetFileInformation = false; public DownUtil(String urlPath, int threadNum) {
this.urlPath = urlPath;
this.defaultTargetPath = "/mnt/sdcard/";
this.threadNum = threadNum;
this.threads = new DownThread[threadNum];
} private HttpURLConnection connection() throws IOException { URL url = new URL(urlPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5 * 1000);
connection.setRequestMethod("GET");
connection.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwave-flash, application/xaml+xml, "
+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
+ "application/x-ms-application, application/vnd.ms-excel, "
+ "application/vnd.ms-powerpoint, application/msword, */*");
connection.setRequestProperty("Accept-Language", "zh-CN");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Connection", "Keep-Alive"); return connection;
} public void getFileInformation() throws IOException { HttpURLConnection connection = connection(); connection.setInstanceFollowRedirects(false); int status = connection.getResponseCode();
if (status != -1) { if (status / 100 == 3) {// 当响应码是302时,说明可以获得重定向的资源地址
// 得到文件名(此方法不能正确的获取所有url的资源文件名)
String name = connection.getHeaderField("Location");
name = URLDecoder.decode(name.substring(name.lastIndexOf('/')), "UTF-8");
this.fileName = name;
} // 得到文件大小
this.fileSize = connection.getContentLength();
if (fileSize <= 0) {
isGetFileInformation = false;
} else {
isGetFileInformation = true;
}
connection.disconnect(); } else { connection.disconnect();
isGetFileInformation = false; } } public boolean download(String targetPath, String fileName) throws IOException { if (isGetFileInformation == false) {
getFileInformation();
} if (isGetFileInformation) { String absFilePath = targetPath + fileName; int currentPartSize = (fileSize / threadNum) + 1;// 每一部分需要下载的大小,注意此处加1是为了避免不能整除带来的误差
RandomAccessFile file = new RandomAccessFile(absFilePath, "rw");
file.setLength(fileSize);
file.close();
for (int i = 0; i < threadNum; i++) {
int startPos = i * currentPartSize;
RandomAccessFile currentPart = new RandomAccessFile(absFilePath, "rw");// 打开目标文件
currentPart.seek(startPos);
threads[i] = new DownThread(startPos, currentPartSize, currentPart);
threads[i].start(); } return true;
} else {
return false; }
} public boolean download() throws IOException {
if (isGetFileInformation) { return download(this.defaultTargetPath, this.getFileName()); } else {
getFileInformation();
return download(this.defaultTargetPath, this.getFileName()); } } public double getCompleteRate() { int sumSize = 0;
for (int i = 0; i < threadNum; i++) { sumSize += threads[i].length;
} return sumSize * 1.0 / fileSize; } public String getDefaultTargetPath() {
return defaultTargetPath;
} public int getFileSize() {
return fileSize;
} public String getFileName() {
return fileName;
} public void setFileName(String fileName) {
this.fileName = fileName;
} public boolean isGetFileInformation() {
return isGetFileInformation;
} private class DownThread extends Thread {
private int startPos;
private int currentPartSize;
private RandomAccessFile currentPart;
int length; // 该线程已经下载的字节数 public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) { this.startPos = startPos;
this.currentPartSize = currentPartSize;
this.currentPart = currentPart;
} @Override
public void run() { try { HttpURLConnection connection = connection();
int endPos = startPos + currentPartSize;
connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);// 使用http来设置一个文件的下载范围(startPos-endPos)
InputStream inStream = connection.getInputStream();
// inStream.skip(startPos); // skip函数有时候不起作用
byte[] buffer = new byte[1024];
int hasRead = 0;
while (length < currentPartSize && (hasRead = inStream.read(buffer)) > 0) { currentPart.write(buffer, 0, hasRead);
length = length + hasRead; } inStream.close();
currentPart.close();
connection.disconnect(); } catch (MalformedURLException e2) {
e2.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} } } }
下面是界面的逻辑代码:
package com.example.urltest; import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask; public class MultiThreadDown extends Activity {
EditText url, target;
Button downButton;
ProgressBar bar;
ProgressDialog progressDialog;
View downView;
DownUtil downUtil;
private int mDownStatus;
private int threadNum = 6; // 默认的线程数
android.os.Handler handler = new android.os.Handler() { @Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {
bar.setProgress(mDownStatus);
if (mDownStatus >= 100) {
Toast.makeText(MultiThreadDown.this, "下载完成", Toast.LENGTH_SHORT).show();
}
// Log.i("csx", "" + mDownStatus); }
} }; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.layout_down);
url = (EditText) findViewById(R.id.url); downButton = (Button) findViewById(R.id.down);
bar = (ProgressBar) findViewById(R.id.bar);
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("尝试连接");
progressDialog.setMessage("正在连接...");
downButton.setOnClickListener(new DownButtonOnClickListener()); } private class DownButtonOnClickListener implements OnClickListener { EditText targetFilePath, fileName;
TextView fileSize;
Thread connectionThread; public Thread instanceOfConnectionThread() {
return new Thread() { @Override
public void run() {
try {
downUtil.getFileInformation(); } catch (IOException e1) {
e1.printStackTrace();
} } };
} @Override
public void onClick(View v) { String urlPath = url.getText().toString();
if (urlPath == null || urlPath.equals("")) {
return;
}
progressDialog.show();
downUtil = new DownUtil(urlPath, threadNum);
connectionThread = instanceOfConnectionThread();
connectionThread.start(); int connectionNum = 3;
while (!downUtil.isGetFileInformation() && connectionNum > 0) {// 循环请求连接,如果3次之后还没有连接成功,就退出
if (!connectionThread.isAlive()) {
connectionThread = null;
connectionThread = instanceOfConnectionThread();
connectionThread.start();
connectionNum--;
} } progressDialog.cancel();
if (!downUtil.isGetFileInformation()) {
Toast.makeText(MultiThreadDown.this, "请求失败!", Toast.LENGTH_SHORT).show();
return;
}
downView = getLayoutInflater().inflate(R.layout.layout_download_view, null);
targetFilePath = (EditText) downView.findViewById(R.id.editText_target_path);
fileName = (EditText) downView.findViewById(R.id.editText_file_name);
fileSize = (TextView) downView.findViewById(R.id.textView_file_size);
targetFilePath.setText(downUtil.getDefaultTargetPath());
fileName.setText(downUtil.getFileName());
fileSize.append("" + ((double) downUtil.getFileSize()) / 1024 + "k"); new AlertDialog.Builder(MultiThreadDown.this).setView(downView)
.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
if (!downUtil.isGetFileInformation()) {
dialog.dismiss();
return;
}
final String path = targetFilePath.getText().toString();
final String name = fileName.getText().toString(); new Thread() { @Override
public void run() {
try {
downUtil.download(path, name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} final Timer timer = new Timer();
TimerTask task = new TimerTask() { @Override
public void run() { mDownStatus = (int) (downUtil.getCompleteRate() * 100);
handler.sendEmptyMessage(0x123);
if (mDownStatus >= 100) {
timer.cancel();
} }
};
timer.schedule(task, 0, 100); } }.start(); }
}).setNegativeButton("取消", null)
.setTitle(downUtil.isGetFileInformation() ? "链接可用" : "链接不可用").show(); }
} }
下面是主页面布局:layout_down.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="要下载的资源的URL:" /> <EditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="在在这里输入URL" /> <Button
android:id="@+id/down"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下载" />
<!-- 定义一个水平进度条,用于显示下载进度 --> <ProgressBar
android:id="@+id/bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100" />
</LinearLayout>
</ScrollView> </LinearLayout>
下面是下载选项dialog布局:layout_download_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载路径:" /> <EditText
android:id="@+id/editText_target_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" > <requestFocus />
</EditText> <TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件名:" /> <EditText
android:id="@+id/editText_file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ems="10" /> <TextView
android:id="@+id/textView_file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件大小:" /> </LinearLayout>
效果图如下:输入URL,点击下载弹出对话框,输入路径和文件名 点击确定开始下载
Android版多线程下载器核心代码分享的更多相关文章
- 教你如何在 Android 使用多线程下载文件
# 教你如何在 Android 使用多线程下载文件 前言 在 Android 日常开发中,我们会经常遇到下载文件需求,这里我们也可以用系统自带的 api DownloadManager 来解决这个问题 ...
- Android中多线程下载列表的封装实现(含进度反馈)
来源:http://blog.csdn.net/u011638883/article/details/17347015 实现了一下Android中的文件多线程下载模块,支持自定义线程数.断点续传.下载 ...
- <基于Qt与POSIX线程>多线程下载器的简易搭建
原创博客,转载请联系博主! 本项目已托管到本人Git远程库:https://github.com/yue9944882/Snow 项目目标 Major Functionality 开发环境: Ce ...
- python10min系列之多线程下载器
今天群里看到有人问关于python多线程写文件的问题,联想到这是reboot的架构师班的入学题,我想了一下,感觉坑和考察的点还挺多,可以当成一个面试题来问,简单说一下我的想法和思路吧,涉及的代码和注释 ...
- 图解:HTTP 范围请求,助力断点续传、多线程下载的核心原理
题图:by Charles Loyer 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header) ...
- Android之——多线程下载演示样例
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46883927 一.概述 说到Android中的文件下载.Android API中明 ...
- 06-python进阶-多线程下载器练手
我们需要用python 写一个多线程的下载器 我们要先获取这个文件的大小 然后将其分片 然后启动多线程 分别去下载 然后将其拼接起来 #!/usr/bin/env python#coding:utf- ...
- Java多线程下载器FileDownloader(支持断点续传、代理等功能)
前言 在我的任务清单中,很早就有了一个文件下载器,但一直忙着没空去写.最近刚好放假,便抽了些时间完成了下文中的这个下载器. 介绍 同样的,还是先上效果图吧. Jar包地址位于 FileDownload ...
- java编写的Http协议的多线程下载器
断点下载器还在实现中...... //////////////////////////////////界面/////////////////////////////////////////// pac ...
随机推荐
- 【转载】linux 技巧:使用 screen 管理你的远程会话
转自:https://www.ibm.com/developerworks/cn/linux/l-cn-screen/ 总结 启动并进入一个screen会话:screen 或者 screen -S 名 ...
- [转]2-SAT问题及其算法
转自:http://www.cppblog.com/MatoNo1/archive/2011/07/13/150766.html [2-SAT问题]现有一个由N个布尔值组成的序列A,给出一些限制关系, ...
- 【ACM/ICPC2013】树形动态规划专题
前言:按照计划,昨天应该是完成树形DP7题和二分图.最大流基础专题,但是由于我智商实在拙计,一直在理解树形DP的思想,所以第二个专题只能顺延到今天了.但是昨天把树形DP弄了个5成懂我是很高兴的!下面我 ...
- hdu3681--Prison Break(TSP+二分)
好难的一道题. 题意:一个机器人要逃出监狱,每走一步消耗一点电量,初始时电量是满的.给一个n*m(n,m<=15)的字符数组代表监狱,F代表起始点,G代表补充满电量,每个G只能补充一次,Y代表开 ...
- Redis+Spring缓存实例(windows环境,附实例源码及详解)
原文出处: 小宝鸽 一.Redis了解 1.1.Redis介绍: redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串). ...
- hdoj 4183 Pahom on Water
Pahom on Water Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- nyoj 540 奇怪的排序
奇怪的排序 时间限制:1000 ms | 内存限制:65535 KB 难度:1 描述 最近,Dr. Kong 新设计一个机器人Bill.这台机器人很聪明,会做许多事情.惟独对自然数的理解与人类 ...
- (一)Redis初学教程之安装篇
1.下载windows下Redis服务安装程序(有32位的和64位的,识操作系统安装) 下载地址:https://github.com/dmajkic/redis/downloads 2.安装教程(详 ...
- SPOJ 3273 - Order statistic set , Treap
点击打开链接 题意: 集合S支持一下四种操作: INSERT(S,x) : 假设S中没有x,则插入x DELETE(S,x): 假设S中有x,则删除x K-TH(S): ...
- myeclipse断点调试
(转) 作为开发者,掌握开发环境下的调试技巧十分有必要.去年就想把关于Eclipse断点调试总结下了.因为对时间的掌控程度仍需极大提高,结果拖到今年才写了此篇博文.关于java调试技术还有非常多.如J ...