热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android实现网络多线程文件下载

这篇文章主要介绍了Android实现网络多线程文件下载的相关资料,需要的朋友可以参考下

实现原理

(1)首先获得下载文件的长度,然后设置本地文件的长度。

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:

(网上找的图)

例如10M大小,使用3个线程来下载,

线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M

下载开始位置:线程id*每条线程下载的数据长度 = ?

下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

之前练习时的一个demo,不多说了,直接上代码吧,有关断点续传,需要使用数据库,不再加了,网上有很多成熟的项目可以直接用。

实例

MainApp:

package com.amos.app; 
import java.io.File; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLConnection; 
import com.amos.download.R; 
import android.annotation.SuppressLint; 
import android.app.Activity; 
import android.os.Bundle; 
import android.os.Environment; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.ProgressBar; 
import android.widget.TextView; 
import android.widget.Toast; 
/** 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class MainApp extends Activity implements OnClickListener { 
private static final String TAG = MainApp.class.getSimpleName(); 
/** 显示下载进度TextView */ 
private TextView mMessageView; 
/** 显示下载进度ProgressBar */ 
private ProgressBar mProgressbar; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.progress_activity); 
findViewById(R.id.download_btn).setOnClickListener(this); 
mMessageView = (TextView) findViewById(R.id.download_message); 
mProgressbar = (ProgressBar) findViewById(R.id.download_progress); 
} 
@Override 
public void onClick(View v) { 
if (v.getId() == R.id.download_btn) { 
doDownload(); 
} 
} 
/** 
* 使用Handler更新UI界面信息 
*/ 
@SuppressLint("HandlerLeak") 
Handler mHandler = new Handler() { 
@Override 
public void handleMessage(Message msg) { 
mProgressbar.setProgress(msg.getData().getInt("size")); 
float temp = (float) mProgressbar.getProgress() 
/ (float) mProgressbar.getMax(); 
int progress = (int) (temp * 100); 
if (progress == 100) { 
Toast.makeText(MainApp.this, "下载完成!", Toast.LENGTH_LONG).show(); 
} 
mMessageView.setText("下载进度:" + progress + " %"); 
} 
}; 
/** 
* 下载准备工作,获取SD卡路径、开启线程 
*/ 
private void doDownload() { 
// 获取SD卡路径 
String path = Environment.getExternalStorageDirectory() 
+ "/amosdownload/"; 
File file = new File(path); 
// 如果SD卡目录不存在创建 
if (!file.exists()) { 
file.mkdir(); 
} 
// 设置progressBar初始化 
mProgressbar.setProgress(0); 
// 简单起见,我先把URL和文件名称写死,其实这些都可以通过HttpHeader获取到 
String downloadUrl = "http://gdown.baidu.com/data/wisegame/91319a5a1dfae322/baidu_16785426.apk"; 
String fileName = "baidu_16785426.apk"; 
int threadNum = 5; 
String filepath = path + fileName; 
Log.d(TAG, "download file path:" + filepath); 
downloadTask task = new downloadTask(downloadUrl, threadNum, filepath); 
task.start(); 
} 
/** 
* 多线程文件下载 
* 
* @author yangxiaolong 
* @2014-8-7 
*/ 
class downloadTask extends Thread { 
private String downloadUrl;// 下载链接地址 
private int threadNum;// 开启的线程数 
private String filePath;// 保存文件路径地址 
private int blockSize;// 每一个线程的下载量 
public downloadTask(String downloadUrl, int threadNum, String fileptah) { 
this.downloadUrl = downloadUrl; 
this.threadNum = threadNum; 
this.filePath = fileptah; 
} 
@Override 
public void run() { 
FileDownloadThread[] threads = new FileDownloadThread[threadNum]; 
try { 
URL url = new URL(downloadUrl); 
Log.d(TAG, "download file http path:" + downloadUrl); 
URLConnection cOnn= url.openConnection(); 
// 读取下载文件总大小 
int fileSize = conn.getContentLength(); 
if (fileSize <= 0) { 
System.out.println("读取文件失败"); 
return; 
} 
// 设置ProgressBar最大的长度为文件Size 
mProgressbar.setMax(fileSize); 
// 计算每条线程下载的数据长度 
blockSize = (fileSize % threadNum) == 0 &#63; fileSize / threadNum 
: fileSize / threadNum + 1; 
Log.d(TAG, "fileSize:" + fileSize + " blockSize:"); 
File file = new File(filePath); 
for (int i = 0; i 

FileDownloadThread:

package com.amos.app; 
import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.IOException; 
import java.io.RandomAccessFile; 
import java.net.URL; 
import java.net.URLConnection; 
import android.util.Log; 
/** 
* 文件下载类 
* 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class FileDownloadThread extends Thread { 
private static final String TAG = FileDownloadThread.class.getSimpleName(); 
/** 当前下载是否完成 */ 
private boolean isCompleted = false; 
/** 当前下载文件长度 */ 
private int downloadLength = 0; 
/** 文件保存路径 */ 
private File file; 
/** 文件下载路径 */ 
private URL downloadUrl; 
/** 当前下载线程ID */ 
private int threadId; 
/** 线程下载数据长度 */ 
private int blockSize; 
/** 
* 
* @param url:文件下载地址 
* @param file:文件保存路径 
* @param blocksize:下载数据长度 
* @param threadId:线程ID 
*/ 
public FileDownloadThread(URL downloadUrl, File file, int blocksize, 
int threadId) { 
this.downloadUrl = downloadUrl; 
this.file = file; 
this.threadId = threadId; 
this.blockSize = blocksize; 
} 
@Override 
public void run() { 
BufferedInputStream bis = null; 
RandomAccessFile raf = null; 
try { 
URLConnection cOnn= downloadUrl.openConnection(); 
conn.setAllowUserInteraction(true); 
int startPos = blockSize * (threadId - 1);//开始位置 
int endPos = blockSize * threadId - 1;//结束位置 
//设置当前线程下载的起点、终点 
conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); 
System.out.println(Thread.currentThread().getName() + " bytes=" 
+ startPos + "-" + endPos); 
byte[] buffer = new byte[1024]; 
bis = new BufferedInputStream(conn.getInputStream()); 
raf = new RandomAccessFile(file, "rwd"); 
raf.seek(startPos); 
int len; 
while ((len = bis.read(buffer, 0, 1024)) != -1) { 
raf.write(buffer, 0, len); 
downloadLength += len; 
} 
isCompleted = true; 
Log.d(TAG, "current thread task has finished,all size:" 
+ downloadLength); 
} catch (IOException e) { 
e.printStackTrace(); 
} finally { 
if (bis != null) { 
try { 
bis.close(); 
} catch (IOException e) { 
e.printStackTrace(); 
} 
} 
if (raf != null) { 
try { 
raf.close(); 
} catch (IOException e) { 
e.printStackTrace(); 
} 
} 
} 
} 
/** 
* 线程文件是否下载完毕 
*/ 
public boolean isCompleted() { 
return isCompleted; 
} 
/** 
* 线程下载文件长度 
*/ 
public int getDownloadLength() { 
return downloadLength; 
} 
}

效果图:


Log控制台:

可以看到文件总大小、我们创建的5个线程每个负责下载的区间

SD卡:

关于Android实现网络多线程文件下载小编就给大家介绍这么多,希望对大家有所帮助!同时也非常感谢大家一直以来对网站的支持!


推荐阅读
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • PHP开发人员薪资水平分析:工程师平均工资概况
    PHP开发人员薪资水平分析:工程师平均工资概况 ... [详细]
  • Windows 10系统对Intel服务器的影响:来自微软官网的下载选项分析 ... [详细]
  • 【Linux进阶指南】第一阶段第三课:体验与部署Ubuntu系统
    在正式踏上Linux学习之旅之前,本课程将引导你深入体验和部署Ubuntu系统。通过详细的操作步骤和实践演练,你将掌握Ubuntu的基本安装、配置及常用命令,为后续的进阶学习打下坚实的基础。此外,课程还将介绍如何解决常见问题和优化系统性能,帮助你更加高效地使用Ubuntu。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 通过 NuGet 获取最新版本的 Rafy 框架及其详细文档
    为了帮助开发者更便捷地使用Rafy领域实体框架,我们已将最新版的Rafy框架程序集上传至nuget.org,并同步发布了最新版本的Rafy SDK至Visual Studio。此外,我们还提供了详尽的文档和示例,以确保开发者能够快速上手并充分利用该框架的强大功能。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • 概率与期望动态规划的深入探讨与应用分析
    本文深入探讨了概率与期望动态规划的基本原理及其在实际问题中的应用。概率是指某一事件发生的可能性大小,用P(A)表示。若某一事件的所有可能结果共有n种,且每种结果出现的概率相等,而事件A包含其中的m种结果,则该事件的概率P(A)为m/n。例如,在投掷骰子的情况下,如果事件A定义为掷出偶数点,由于共有3种偶数点(2、4、6),而总共有6种可能的结果,因此P(A)为1/2。文章进一步分析了概率与期望动态规划在复杂场景下的建模方法和求解策略,并通过具体实例展示了其在决策优化和风险管理中的应用价值。 ... [详细]
  • 本文深入解析了Bitmap与Byte数组之间高效转换的方法,探讨了不同场景下的最优实现策略,提供了详尽的代码示例和性能对比分析,旨在帮助开发者在图像处理和数据传输中提升效率和减少资源消耗。 ... [详细]
  • 本文源自极分享,详细内容请参阅原文。技术债务如同信用卡负债,随着时间推移,修复成本会越来越高,因此程序员必须对此有深刻认识。此外,团队应致力于培养一种持续维护和优化代码的文化,以减少技术债务的累积。 ... [详细]
  • 1. 设置用户密码:使用 `slappasswd` 工具生成加密密码,确保账户安全。具体步骤如下:输入命令 `slappasswd -s NewPassword`,系统将提示重新输入新密码,并生成加密后的哈希值 {SSHA}xxxxxxxxxxxxxxxxx。2. 编写配置文件:编辑 `vildapus` 配置文件,添加必要的用户账户信息,以确保新用户能够顺利登录系统。 ... [详细]
  • 如何在Android设备上通过应用程序创建浏览器书签 ... [详细]
  • 虚拟机网络设置与数据库远程连接优化指南
    本文针对个人计算机上虚拟机网络配置与数据库远程连接的问题,提供了一套详细的优化指南。在探讨远程数据库访问前,需确保网络配置正确,特别是桥接模式的设置。通过合理的网络配置,可以有效解决因虚拟机或网络问题导致的连接失败,提升远程访问的稳定性和效率。 ... [详细]
  • 本文详细介绍了 Windows API 中的按钮控件及其应用实例。主要功能包括:1. `CheckDlgButton` 用于更改对话框中按钮的选中状态;2. `CheckRadioButton` 用于设置单选按钮的选中状态。此外,还探讨了按钮控件在实际开发中的多种应用场景,帮助开发者更好地理解和使用这些功能。 ... [详细]
  • 在学习LVM(逻辑卷管理)技术的过程中,我对MD(多设备)、DM(设备映射器)以及逻辑设备和RAID的实现有了深入的理解。LVM2架构主要由DM主模块及其多个子模块组成,其中linear子模块用于创建线性设备,类似于简单的磁盘分区拼接。此外,还探讨了其他子模块如striped、mirror等在提高性能和数据冗余方面的应用。通过实际操作,我掌握了LVM的基本配置和管理方法,能够灵活应对不同存储需求。 ... [详细]
author-avatar
淑圣承琦9_416
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有