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来进行定位。

当然也并非开的线程数越多下载的速度也就越快,因为线程越多对于程序处理这些线程也是一种负担,过多的话反而会降低下载的速度,所以要合理运用。

标签:Android,断点续传,下载
0
投稿

猜你喜欢

  • C#中try...catch的使用与常见面试题分享

    2022-10-22 16:30:35
  • Java分布式锁的概念与实现方式详解

    2022-07-11 19:33:57
  • java设计模式(实战)-责任链模式

    2022-12-24 23:07:53
  • Java实现自动压缩文件并加密的方法示例

    2023-05-08 03:33:18
  • SpringBoot中整合Minio文件存储的安装部署过程

    2022-02-21 01:28:14
  • Android仿支付宝中余额宝的数字动画效果

    2021-10-17 08:32:54
  • C#判断数据类型的简单示例代码

    2023-09-22 22:22:48
  • 详解Java递归实现树形结构的两种方式

    2023-02-18 07:24:47
  • SpringBoot Schedule调度任务的动态管理

    2023-09-22 04:34:15
  • 浅谈C# 中的委托和事件

    2021-06-06 18:53:07
  • C#使用Socket实现服务器与多个客户端通信(简单的聊天系统)

    2022-03-08 23:48:07
  • C# 指针内存控制Marshal内存数据存储原理分析

    2021-09-22 04:05:00
  • Android ActionBar搜索功能用法详解

    2023-01-24 21:15:02
  • C# GDI+实现时钟表盘

    2023-06-20 07:11:32
  • 详解C# partial 关键字的使用

    2023-06-07 20:46:09
  • 轻松掌握Java建造者模式

    2023-11-06 15:24:38
  • 使用BindingResult 自定义错误信息

    2023-09-02 17:43:01
  • jdbc与druid连接池的使用详解

    2023-09-18 17:50:11
  • Java 虚拟机栈详解分析

    2021-08-29 10:04:55
  • flutter text组件使用示例详解

    2022-07-11 11:08:42
  • asp之家 软件编程 m.aspxhome.com