欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现网络多线程断点续传下载功能

程序员文章站 2022-06-30 08:26:24
我们编写的是andorid的http协议多线程断点下载应用程序。直接使用单线程下载http文件对我们来说是一件非常简单的事。那么,多线程断点需要什么功能? 1.多线程...

我们编写的是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来进行定位。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。