文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 08:47

关注

实现原理

(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; 
 
public class MainApp extends Activity implements OnClickListener { 
private static final String TAG = MainApp.class.getSimpleName(); 
 
private TextView mMessageView; 
 
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(); 
} 
} 
 
@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 + " %"); 
} 
}; 
 
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(); 
} 
 
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 ? fileSize / threadNum 
: fileSize / threadNum + 1; 
Log.d(TAG, "fileSize:" + fileSize + " blockSize:"); 
File file = new File(filePath); 
for (int i = 0; i < threads.length; i++) { 
// 启动线程,分别下载每个线程需要下载的部分 
threads[i] = new FileDownloadThread(url, file, blockSize, 
(i + 1)); 
threads[i].setName("Thread:" + i); 
threads[i].start(); 
} 
boolean isfinished = false; 
int downloadedAllSize = 0; 
while (!isfinished) { 
isfinished = true; 
// 当前所有线程下载总量 
downloadedAllSize = 0; 
for (int i = 0; i < threads.length; i++) { 
downloadedAllSize += threads[i].getDownloadLength(); 
if (!threads[i].isCompleted()) { 
isfinished = false; 
} 
} 
// 通知handler去更新视图组件 
Message msg = new Message(); 
msg.getData().putInt("size", downloadedAllSize); 
mHandler.sendMessage(msg); 
// Log.d(TAG, "current downloadSize:" + downloadedAllSize); 
Thread.sleep(1000);// 休息1秒后再读取下载进度 
} 
Log.d(TAG, " all of downloadSize:" + downloadedAllSize); 
} catch (MalformedURLException e) { 
e.printStackTrace(); 
} catch (IOException e) { 
e.printStackTrace(); 
} catch (InterruptedException e) { 
e.printStackTrace(); 
} 
} 
} 
}

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; 
 
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; 
 
private int threadId; 
 
private int blockSize; 
 
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实现网络多线程文件下载小编就给大家介绍这么多,希望对大家有所帮助!同时也非常感谢大家一直以来对编程网网站的支持!

您可能感兴趣的文章:android中webview控件和javascript交互实例Android WebView使用方法详解 附js交互调用方法Android开发之WebView组件的使用解析Android使用WebView播放flash的方法Android实现WebView删除缓存的方法Android中WebView图片实现自适应的方法Android zip文件下载和解压实例Android实现文件下载进度显示功能Android 文件下载三种基本方式Android 将文件下载到指定目录的实现代码android实现文件下载功能Android编程使用WebView实现文件下载功能的两种方法


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯