Android实现网络多线程断点续传下载功能
作者:liu_xiaohuan 发布时间:2021-05-29 18:22:24
我们编写的是Andorid的HTTP协议多线程断点下载应用程序。直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。那么,多线程断点需要什么功能?
1.多线程下载
2.支持断点
使用多线程的好处:使用多线程下载会提升文件下载的速度
原理
多线程下载的原理就是将要下载的文件分成若干份,其中每份都使用一个单独的线程进行下载,这样对于文件的下载速度自然就提高了许多。
既然要分成若干部分分工下载,自然要知道各个线程自己要下载的起始位置,与要下载的大小。所以我们要解决线程的分配与各个线程定位到下载的位置。
封装
对于多线程下载我们可以将其封装到一个工具类中DownUtil,向其中传入下载的链接、文件存储路径、需要下载的线程数
分配线程
这里通过HttpURLConnection进行网络请求下载,通过getContentLength()方法获取下载文件的总大小,再对其平均分配各个线程需要下载的大小。这样就确定了下载的大小,下面就是定位到各个线程的开始位置进行下载,这里可以使用RandomAccessFile来 * 到要下载的位置,它的seek()方法可以进行定位。
线程下载
下面就是各个线程的下载DownThread,上面已经得到了各个线程要下载的初始位置,所以可以通过获取网络请求的输入流InputStream,通过skip()方法跳跃到指定位置进行读取数据,再写入到RandomAccessFile文件中
一、 编写基本的UI,三个TextView,分别显示文件名、下载进度和下载速度,一个ProgressBar。二个Button,分别用于开始下载、暂停下载和取消下载。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.linux.continuedownload.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_marginLeft="80dp"
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_marginLeft="80dp"
android:id="@+id/speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<ProgressBar
android:visibility="invisible"
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始下载" />
<Button
android:layout_marginLeft="20dp"
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停下载" />
<Button
android:layout_marginLeft="20dp"
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消下载" />
</LinearLayout>
</LinearLayout>
在onCreate方法中绑定开始下载按钮事件:点击start按钮,设置进度条可见,并且设置start的Action,启动服务。
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText(fileInfo.getFileName());
progressBar.setVisibility(View.VISIBLE);
// 通过Intent传递参数给service
Intent intent = new Intent(MainActivity.this, DownloadService.class);
intent.setAction(DownloadService.ACTION_START);
intent.putExtra("fileInfo", fileInfo);
startService(intent);
}
});
在onCreate方法中绑定暂停下载按钮事件:点击stop按钮,设置stop的Action,启动服务。
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通过Intent传递参数给service
Intent intent = new Intent(MainActivity.this, DownloadService.class);
intent.setAction(DownloadService.ACTION_STOP);
intent.putExtra("fileInfo", fileInfo);
startService(intent);
}
});
在onCreate方法中绑定取消下载按钮事件:点击cancel按钮,设置cancel的Action,启动服务,之后更新UI。
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通过Intent传递参数给service
Intent intent = new Intent(MainActivity.this, DownloadService.class);
intent.setAction(DownloadService.ACTION_CANCEL);
intent.putExtra("fileInfo", fileInfo);
startService(intent);
// 更新textView和progressBar的显示UI
textView.setText("");
progressBar.setVisibility(View.INVISIBLE);
progressView.setText("");
speedView.setText("");
}
});
注册广播,用于Service向Activity传递一些下载进度信息:
// 静态注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadService.ACTION_UPDATE);
registerReceiver(broadcastReceiver, intentFilter);
/**
* 更新UI
*/
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DownloadService.ACTION_UPDATE.equals(intent.getAction())) {
int finished = intent.getIntExtra("finished", 0);
int speed = intent.getIntExtra("speed", 0);
Log.i("Main", finished + "");
progressBar.setProgress(finished);
progressView.setText(finished + "%");
speedView.setText(speed + "KB/s");
}
}
};
三、 在AndroidManifest.xm文件中声明权限,定义服务
<service android:name="com.huhx.services.DownloadService" android:exported="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
总结
多线程的关键就是分配好需要下载的进程,定位进程下载的准确位置,获取输入流读取数据,同时写入到文件的相应位置。可以借助RandomAccessFile来进行定位。
当然也并非开的线程数越多下载的速度也就越快,因为线程越多对于程序处理这些线程也是一种负担,过多的话反而会降低下载的速度,所以要合理运用。
猜你喜欢
- Java Lambda 源码分析问题:Lambda 表达式是什么?JVM 内部究竟是如何实现 Lambda 表达式的?为什么要这样实现?一、
- C# 4.0提供了一个dynamic 关键字,那么什么是dynamic,究竟dynamic是如何工作的呢?从最简单的示例开始:static
- 序言之前封装过一个日志注解,打印方法执行信息,功能较为单一不够灵活,近来兴趣来了,想重构下,使其支持表达式语法,以应对灵活的日志打印需求。该
- 1.先下载微信分享的jar包放在lib目录下,并且添加依赖,清单文件添加<activity
- Mybatis表现关联关系比hibernate简单,没有分那么细致one-to-many、many-to-one、one-to-one。而是
- kafka-console-consumer.sh解读kafka-console-consumer.sh 脚本是一个简易的消费者控制台。该
- 下面由我来给大家展示用spring aop实现 * 的例子(电脑打印)下面就看一下具体的代码:先定义一个打印机的接口package aop
- 第一部分 问题描述1.1 具体任务本次作业任务是轨迹压缩,给定一个GPS数据记录文件,每条记录包含经度和维度两个坐标字段,所有记录的经纬度坐
- 本文实例讲述了Java基于Swing实现的打猎射击游戏代码。分享给大家供大家参考。具体实现代码如下:package Game;import
- 本文实例为大家分享了Android实现上下菜单双向滑动的具体代码,供大家参考,具体内容如下这是研究了网上大神双向左右滑动后实现的上下双向滑动
- JPA like 模糊查询 语法格式public List<InstitutionInfo> getAllInstitution
- mybatis多个区间处理如图:要实现车辆数不同区间查询条件思路a.前端传数组,数组里面放"1-5"String类型值
- ArrayList底层维护的是一个动态数组,每个ArrayList实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列
- 效果图如下所示:先给大家说下实现android 跳转到通讯录的实现思路:1.点击跳转到通讯录界面2.获取通讯录姓名和手机号码3.回调显示姓名
- 把最近听的写的一些题目做下笔记!1.下列程序的执行,说法错误的是 ( ABC )public class MultiCatch
- 1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有
- 关于[Cannot determine value type from string ‘xxx’]的
- java 网络编程java.net 类 InetAddress 此类表示互联网协议 (IP) 地址。 会抛出异常 UnknownHostEx
- 引导语线程池我们在工作中经常会用到。在请求量大时,使用线程池,可以充分利用机器资源,增加请求的处理速度,本章节我们就和大家一起来学习线程池。
- 本文实例讲述了C#纹理画刷TextureBrush用法。分享给大家供大家参考。具体如下:using System;using System.