单线程下载很简单,就是开启一个线程去下载资源再进行本地保存;
多线程下载是通过RandomAccessFile(随机文件读写操作类)来设置每个线程读取文件的起始点位置,起始点之间的长度即为该线程需要下载的文件大小
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
这样比如文件大小:size,线程数:threads,则每个线程的下载量:size/threads;但是这是整除的情况,如果考虑到不能整除的情况:则前threads-1个线程下载量为size/threads,最后一个线程的下载量:size/threads+size%threads
package file.down;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.security.auth.PrivateCredentialPermission;
import android.R.integer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewDebug.FlagToString;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
public class File_downActivity extends Activity {
private Button but1,but2;
private EditText etUrl;
private ProgressBar bar1,bar2;
private TextView tv1,tv2;
private boolean flag = true;
private int temp = 0;
private int downLoadedSize = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etUrl = (EditText) findViewById(R.id.downloadUrl);
but1 = (Button) findViewById(R.id.but1);
but2 = (Button) findViewById(R.id.but2);
bar1 = (ProgressBar) findViewById(R.id.downloadProgressBar1);
bar2 = (ProgressBar) findViewById(R.id.downloadProgressBar2);
tv1 = (TextView) findViewById(R.id.tv1);
tv2 = (TextView) findViewById(R.id.tv2);
//单线程下载
but1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(DownUtil.isExistSdCard()){
if(DownUtil.checkNet(File_downActivity.this)){
if(DownUtil.creatDir(DownUtil.path1)){
thread.start();
}
}
}
}
});
//多线程下载
but2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mulThread.start();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
DownUtil.downLoadSize = 0;
}
/**
* 单线程下载
*/
private Thread thread = new Thread(new Runnable() {
@Override
public void run() {
DownUtil.fileDown1(etUrl.getText().toString(), DownUtil.savePath1, handler);
bar1.setMax(DownUtil.fileSize);
}
});
/**
* 多线程下载(主线程类)
*/
private Thread mulThread = new Thread(new Runnable() {
private int blockSize,downLoadSizeMore;
private int threadNum = 5;//线程数
@Override
public void run() {
// MulDownThread[] threads = new MulDownThread[threadNum];
try {
URL url = new URL(etUrl.getText().toString());
URLConnection connection = url.openConnection();
DownUtil.fileSize2 = connection.getContentLength();
if(DownUtil.fileSize2 <= 0){
return;
}
} catch (Exception e) {
e.printStackTrace();
}
//计算每个线程下载的数据量
blockSize = DownUtil.fileSize2 / threadNum;
//解决整除后余下的数据量
downLoadSizeMore = DownUtil.fileSize2 % threadNum;
bar2.setMax(100);
if(DownUtil.creatDir(DownUtil.path2)){
File file = new File(DownUtil.savePath2 + "/" + etUrl.getText().toString().substring(etUrl.getText().toString().lastIndexOf("/") + 1));
for(int i=0;i<threadNum;i++){
if(i < threadNum - 1){
//启动线程,分别下载文件
MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize - 1,handler);
thread.start();
}else{//最后那个线程下载的文件长度要等于每个线程平均下载量加上整除后的余数
MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize - 1 + downLoadSizeMore,handler);
thread.start();
}
// //启动线程,分别下载文件
// MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize -1);
// thread.start();
// handler.sendEmptyMessage(10);
}
// boolean finished = false;
// while(!finished){
// //先把整除的余数搞定
// downLoadedSize = downLoadSizeMore;
// finished = true;
// for(int i = 0;i<threads.length;i++){
// downLoadedSize += threads[i].downLoadSize;
// if(!threads[i].isFinisthed){
// finished = false;
// }
// }
// handler.sendEmptyMessage(10);
// }
}
}
});
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
tv1.setText("无法获取文件大小");
break;
case -1:
tv1.setText("下载完成");
bar1.setProgress(100);
but1.setClickable(false);
break;
case 1:
but1.setClickable(false);
int result = Double.valueOf(((Integer.parseInt(msg.obj.toString())*1.0 / DownUtil.fileSize * 100))).intValue();
bar1.setProgress(result);
tv1.setText(result + "%");
break;
case 2:
tv1.setText("文件获取错误");
break;
case 10://多线程下载更新进度条
but2.setClickable(false);
int result2 = (Double
.valueOf((Integer.parseInt(msg.obj.toString()) * 1.0 / DownUtil.fileSize2 * 100)))
.intValue();
bar2.setProgress(result2);
if(result2 == 100){
tv2.setText("下载完成");
}else{
tv2.setText(result2 + "%");
}
break;
}
};
};
}
package file.down;
import java.io.File;
import android.os.Handler;
/**
* 线程类
* @author Administrator
*
*/
public class MulDownThread extends Thread {
private String url;
private File file;
private int startPosition;
private int endPosition;
private Handler handler;
public MulDownThread(String url,File file,int startPosition,int endPosition,Handler handler){
this.url = url;
this.file = file;
this.startPosition = startPosition;
this.endPosition = endPosition;
this.handler = handler;
}
@Override
public void run() {
DownUtil.fileDown2(url, file, startPosition, endPosition,handler);
}
}
package file.down;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
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.URLConnection;
import android.R.integer;
import android.R.string;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class DownUtil {
//单线程下载目录
public static String path1 = "/down1/";
public static String savePath1;
//多线程下载目录
public static String path2 = "/down2/";
public static String savePath2;
public static String fileName;
public static int fileSize;
public static int fileSize2;
private static int curPosition;
//已下载的文件大小
public static int downLoadSize;
//标示当前线程是否下载完成
public static boolean finished = false;
/**
* 判断sd卡是否存在
* Environment.MEDIA_MOUNTED 判断SD卡是否存在
* @return
*/
public static boolean isExistSdCard(){
boolean flag = true;
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
flag = false;
}
return flag;
}
/**
* 创建目录
* @param dir
* @return
*/
public static boolean creatDir(String dir){
boolean flag = false;
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + dir);
if(!file.exists()){
file.mkdir();
if(file.exists()){
flag = true;
savePath1 = file.getAbsolutePath();
savePath2 = file.getAbsolutePath();
}
}else{
flag = true;
savePath1 = file.getAbsolutePath();
savePath2 = file.getAbsolutePath();
}
return flag;
}
/**
* 检查网络是否可用
* @return
*/
public static boolean checkNet(Context context){
boolean flag = false;
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if(wifi.isConnectedOrConnecting() || mobile.isConnectedOrConnecting()){
flag = true;
}
return flag;
}
/**
* 单线程文件下载
* @param url
* @param path
*/
public static void fileDown1(String url,String path,Handler handler) {
Log.v("=path=", path+"=");
Message message = new Message();
if(!"".equals(url)){
fileName = url.substring(url.lastIndexOf("/") + 1);
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
URL myuUrl = new URL(url);
URLConnection connection = myuUrl.openConnection();
connection.connect();
inputStream = connection.getInputStream();
fileSize = connection.getContentLength();
Log.v("=fileSize=", DownUtil.fileSize+"=");
if(fileSize <= 0){
message.what = 0;
handler.sendMessage(message);
return;
}else{
outputStream = new FileOutputStream(path +"/"+ fileName);
//存储文件
byte buf[] = new byte[inputStream.available()];
int len = 0;
int temp = 0;
Log.v("=available=", inputStream.available()+"=");
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
temp += len;
Message message2 = new Message();
message2.what = 1;
message2.obj = temp;//下载的百分比
handler.sendMessage(message2);
}
Message msg = new Message();
//通知下载完成
msg.what = -1;
handler.sendMessage(msg);
}
} catch (Exception e) {
message.what = 2;
handler.sendMessage(message);
return;
}finally{
try {
if(inputStream != null || outputStream != null){
outputStream.close();
inputStream.close();
}
} catch (Exception e2) {
}
}
}
}
/**
* 多线程下载文件
* @param url
* @param path
* @param handler
*/
public static void fileDown2(String url,File file,int startPosition,int endPosition,Handler handler){
URLConnection connection = null;
InputStream inputStream = null;
BufferedInputStream bis = null;
RandomAccessFile raf = null;
try {
URL url2 = new URL(url);
connection = url2.openConnection();
// connection.connect();
connection.setAllowUserInteraction(true);
// 设置当前线程下载的起点,终点
connection.setRequestProperty("Range", "bytes=" + startPosition + "-"
+ endPosition);
inputStream = connection.getInputStream();
if(fileSize2 <= 0){
return;
}
//对文件进行随机读写操作
raf = new RandomAccessFile(file,"rw");
//设置开始写文件的位置
raf.seek(startPosition);
bis = new BufferedInputStream(inputStream);
//开始循环以流的形式读写文件
// curPosition = startPosition;
//每个线程需要读取文件的长度
// int temp = endPosition - startPosition;
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inputStream.read(buffer)) != -1) {
raf.write(buffer, 0, length);
downLoadSize += length;
Message message = new Message();
message.what = 10;
message.obj = downLoadSize;
handler.sendMessage(message);
}
// while (curPosition < endPosition) {
// int len = bis.read(buffer, 0, temp);
// if(len == -1){
// break;
// }
// Log.v("=len=", "="+len);
// raf.write(buffer, 0, len);
// curPosition += len;
//// if(curPosition > endPosition){
//// downLoadSize += len - (curPosition - endPosition) + 1;
//// Log.v("=downLoadSize=", "="+downLoadSize);
//// }else{
// downLoadSize += len;
//// }
// Message message = new Message();
// message.what = 10;
// message.obj = downLoadSize;
// handler.sendMessage(message);
// }
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(inputStream != null || raf != null || bis != null){
bis.close();
raf.close();
inputStream.close();
}
} catch (Exception e2) {
}
}
}
}
- 大小: 43 KB
分享到:
相关推荐
这是本人开源的一套android单线程多任务断点下载的项目,可支持排队下载,我看网上很多人的下载任务都是只能更新当前界面,我就做了多界面刷新,调用简单只需3个步骤,1、注册下载监听。2、点击下载(自动判断状态)...
android 多线程下载机制,提高下载的速度,同时开启多个线程对同一个文件进行下载。
Android开发中的多线程编程技术资源包 TAG:Android 多线程 应用开发 Alfred整理发布,版权所有!
Android中实现断点续传下载功能,有详细的注释,需要的打包带走。
android 单线程多任务断点排队下载(支持多界面刷新.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
百思不得其解,多线程与单线程操控VCL控件怎么会有这大的差别,编译了32位与64位两个版本,供测试。请高手帮忙解释一下。
基于Android的多线程下载,单纯的下载功能
一个支持多线程断点续传功能的Android下载工具.zip 功能特性 断点续传 支持多线程 (目前版本仅支持单任务单线程,多任务才多线程,未来会继续完善单任务的多线程执行)
android下载框架,支持单线程和多线程断点下载.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
主要介绍了Android多线程+单线程+断点续传+进度条显示下载功能,需要的朋友可以参考下
在多线程编程这块,我们经常要使用Handler(处理),Thread(线程)和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢? 首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而...
利用idhttp进行多线程下载,带进度条显示,可以暂停下载和继续下载,未使用第三方控件,在delphi xe7下测试通过。 昨天发的代码发现一个bug,就是无论几线程,都是从文件首部开始下载,才发现xe7下idhhtp控件的...
多线程下载是加快下载速度的一种方式,通过开启多个线程去执行一个任务..可以使任务的执行速度变快..多线程的任务下载时常都会使用得到..比如说我们手机内部应用宝的下载机制..一定是通过使用了多线程创建的下载器.....
人工智能-项目实践-多任务-一个支持多线程,断点续传功能的Android下载工具 功能特性 断点续传 支持多线程 (目前版本仅支持单任务单线程,多任务才多线程,未来会继续完善单任务的多线程执行) 使用本项目的理由 可靠...
Android 多线程的实例详解 Java多线程方式 1. 继承Thread线程,实现run方法 2. 实现Runnable接口 JAVA单继承性,当我们想将一个已经继承了其他类的子类放到Thread中时,单继承的局限就体现出来了 但是可以实现...
多线程下载。 √ 断点续传支持。 √ 回调接口。 √ 处理异常。 √ 多任务管理。 √ 线程之间的同步通信。 × v1.1.0 有什么新变化? 多任务管理器:帮助您高效管理任务。 优化的代码结构。 如何更新到 v...
如果多线程同时读写(这里的指不同的线程用使用的是不同的Helper实例),后面的就会遇到android.database.sqlite.SQLiteException: database is locked这样的异常。对于这样的问题,解决的办法就是keep single ...
首先来看一下多线程下载的原理。多线程下载就是将同一个网络上的原始文件根据线程个数分成均等份,然后每个单独的线程下载对应的一部分,然后再将下载好的文件按照原始文件的顺序“拼接”起来就构 成了完整的文件了...