单线程下载很简单,就是开启一个线程去下载资源再进行本地保存;
多线程下载是通过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开发中,文件下载是一项常见的任务,尤其在应用需要获取网络...尽管单线程下载简单易懂,但在实际应用中,为了提高下载速度和用户体验,通常会使用多线程或者基于下载库如OkHttp、Volley等更高级的解决方案。
在Android平台上,多线程下载机制是提升应用性能和用户体验的关键技术之一,特别是在处理大文件如应用程序、视频或音频资源的下载场景中。通过利用多线程,我们可以将一个大文件分割成多个小部分,然后同时启动多个...
在Android应用开发中,多线程下载是一项关键技术,它能显著提高大文件下载的效率,尤其是在网络条件不稳定的情况下。断点续传是多线程下载的一个重要特性,允许用户中断下载后,从上次停止的位置继续,提高了用户...
传统的单线程下载方式只有一个线程负责整个文件的下载,而多线程下载则是将大文件分割成多个小块,每个小块由不同的线程独立下载。这样可以同时利用多个网络连接,提高下载速度。 接下来是断点续传的概念。断点续传...
本篇文章将详细探讨如何在Android中实现多线程下载功能,并涉及断点续传技术,以确保下载的高效性和可靠性。我们还将提及提供的`demo.apk`,这是一个实际的演示应用,可供开发者直接安装体验。 ### 一、多线程下载...
在Android应用开发中,多线程下载是一种常见的技术,它能显著提高大文件下载的效率,减少用户等待时间。本文将深入探讨Android多线程下载的原理、实现方式以及优化策略。 首先,我们要理解为什么需要多线程下载。在...
在Android开发中,进行大文件下载时,为了提高效率并充分利用设备资源,通常会采用多线程下载技术。此外,为了提升用户体验,断点续传功能也显得尤为重要,尤其是在网络不稳定或者用户中断下载后,可以从上次停止的...
在Android应用开发中,文件上传是一项常见的任务,尤其是在处理大文件或者需要提高用户交互体验时,多线程技术显得尤为重要。本主题聚焦于"Android多线程文件上传",我们将探讨如何利用多线程技术来优化文件上传过程...
Android提供了一个系统级别的`DownloadManager`服务,它可以处理文件的断点续传,但可能不如自定义实现的多线程下载灵活。 6. **文件读写操作** 在下载过程中,需要使用`RandomAccessFile`进行文件的追加写入,...
在Android平台上,多线程下载是一项重要的技术,它允许应用程序同时从服务器获取数据,从而显著提高了文件下载的速度和效率。本教程将深入讲解如何在Android环境中实现多线程下载功能,以及涉及的相关知识点。 首先...
本篇文章将深入探讨如何在Android环境中实现多线程下载,以提高应用程序的响应速度和用户体验。 首先,理解Android的主线程至关重要。主线程,也被称为UI线程,负责处理用户界面的所有交互。如果在主线程中执行耗时...
而多线程下载则是将文件分成多个部分,每个部分在一个独立的线程中下载,这样可以利用多核处理器的优势,提高下载速度,同时减少因网络波动导致的下载中断。 断点下载则涉及到文件的分块管理和存储。在下载开始前,...
在Android开发中,多线程下载文件是一种常见的优化策略,特别是在处理大文件或者网络环境不稳定的情况下,能够提高下载效率并减少资源浪费。本项目提供的就是一个实现了多线程断点续传功能的Android下载器,它包含...
在Android开发中,多线程图片下载是一个常见的需求,尤其在大数据量或者高并发的情况下,单线程下载图片会严重影响用户体验,因为这可能导致UI线程阻塞,使得应用显得卡顿。这篇博客“Android 多线程图片下载开源...
在Android开发中,多线程下载是一项常见的任务,它能够有效地利用网络资源并提升用户体验。本文将基于提供的标题“Android 多线程下载简单demo之Thread”和描述,深入讲解如何实现一个简单的多线程下载功能。这个...
多线程下载是指将一个大文件分成多个小部分,每个部分由一个单独的线程负责下载。这样可以同时从服务器获取数据,显著提高了下载速度。在Android中,我们可以使用`AsyncTask`或自定义`Thread`来创建下载线程。 2. ...
在多线程下载中,工作线程负责实际的下载任务,而主线程则更新UI,显示下载进度。因此,需要通过`Handler`将下载进度信息发送到主线程,以便实时更新进度条。 在**错误处理**方面,需要考虑网络中断、服务器响应...