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

RxJava2.x+ReTrofit2.x多线程下载文件的示例代码

程序员文章站 2024-03-01 12:50:22
写在前面: 接到公司需求:要做一个apk升级的功能,原理其实很简单,百度也一大堆例子,可大部分都是用框架,要么就是httpurlconnection,实在是不想这么干。正...

写在前面:

接到公司需求:要做一个apk升级的功能,原理其实很简单,百度也一大堆例子,可大部分都是用框架,要么就是httpurlconnection,实在是不想这么干。正好看了两天的rxjava2.x+retrofit2.x,据说这俩框架是目前最火的异步请求框架了。固本文使用rxjava2.x+retrofit2.x实现多线程下载文件的功能。
如果对rxjava2.x+retrofit2.x不太了解的请先去看相关的文档。
大神至此请无视。

思路分析:

思路及其简洁明了,主要分为以下四步

1.获取服务器文件大小.
2.根据文件大小规划线程数量.
3.根据下载内容合并为完整文件.
4.调用安装,安装apk.
功能实现

来,接下来是你们最喜欢的撸代码环节

1.首先看引用

  compile 'io.reactivex:rxjava:latest.release'
  compile 'io.reactivex:rxandroid:latest.release'
  //network - squareup
  compile 'com.squareup.retrofit2:retrofit:latest.release'
  compile 'com.squareup.retrofit2:adapter-rxjava:latest.release'
  compile 'com.squareup.okhttp3:okhttp:latest.release'
  compile 'com.squareup.okhttp3:logging-interceptor:latest.release'

2.构造一个下载接口downloadservice.class

public interface downloadservice {
  @streaming
  @get
  //downparam下载参数,传下载区间使用
  //url 下载链接
  observable<responsebody> download(@header("range") string downparam,@url string url);
}

3.为了使用方便封装了一个retrofithelper.class,主要用于:

a)实例化okhttpclient和retrofit.

  public retrofithelper(string url, downloadprogresslistener listener) {

    downloadprogressinterceptor interceptor = new downloadprogressinterceptor(listener);

    okhttpclient client = new okhttpclient.builder()
        .addinterceptor(interceptor)
        .retryonconnectionfailure(true)
        .connecttimeout(default_timeout, timeunit.seconds)
        .build();
    retrofit = new retrofit.builder()
        .baseurl(url)
        .client(client)
        .addcalladapterfactory(rxjavacalladapterfactory.create())
        .build();
  }

b)封装下载方法,本次下载我使用的是三个下载线程,并没有动态分配,各位可以根据自己的需求去动态分配线程个数

 public observable download(@nonnull final long start, @nonnull final long end, @nonnull final string url, final file file, final subscriber subscriber) {
    string str = "";
    if (end == -1) {
      str = "";
    } else {
      str = end + "";
    }
    return retrofit.create(downloadservice.class).download("bytes=" + start + "-" + str, url).subscribeon(schedulers.io()).unsubscribeon(schedulers.io()).map(new func1<responsebody, responsebody>() {
      @override
      public responsebody call(responsebody responsebody) {
        return responsebody;
      }
    }).observeon(schedulers.computation()).doonnext(new action1<responsebody>() {
      @override
      public void call(responsebody responsebody) {
        //第一次请求全部文件长度
        if (end == -1) {
          try {
            randomaccessfile randomfile = new randomaccessfile(file, "rw");
            randomfile.setlength(responsebody.contentlength());
            long one = responsebody.contentlength() / 3;
            download(0, one, url, file, subscriber).mergewith(download(one, one * 2, url, file, subscriber)).mergewith(download(one * 2, responsebody.contentlength(), url, file, subscriber)).subscribe(subscriber);

          } catch (ioexception e) {
            e.printstacktrace();
          }
        } else {
          fileutils fileutils = new fileutils();
          fileutils.writefile(start, end, responsebody.bytestream(), file);
        }

      }
    }).subscribeon(androidschedulers.mainthread());
  }

 4.调用下载

注:调用下载在mainacitivity中进行,为了直观我们封装了进度拦截器以方便实现进度显示,但是本篇不在叙述进度拦截器的实现过程,如有需要可以留言。

a)实现监听对象

subscriber = new subscriber() {
      @override
      public void oncompleted() {
        log.e("mainactivity", "oncompleted下下载完成");
//        toast.maketext(mainactivity.this, "oncompleted下下载完成", toast.length_long).show();
        installapk("mnt/sdcard/aaaaaaaaa.apk");
      }

      @override
      public void onerror(throwable e) {
        e.printstacktrace();
        log.e("mainactivity", "onerror: " + e.getmessage());
      }

      @override
      public void onnext(object o) {

      }
    };

 b)调用封装的retrofithelper实现下载

 retrofithelper retrofithelper = new retrofithelper("http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/", new downloadprogresslistener() {
      @override
      public void update(long bytesread, long contentlength, boolean done) {

        sharedpf.getsharder().setlong("update", bytesread);
        pro.setprogress((int) ((double) bytesread / contentlength * 100));
        temp++;
        if (temp <= 1) {
          log.e("mainactivity", "update" + bytesread + "");
        }
      }
    });
    retrofithelper.download(0, -1, "qq_718.apk", new file("mnt/sdcard/", "aaaaaaaaa.apk"), subscriber).subscribe(new subscriber() {
      @override
      public void oncompleted() {

      }

      @override
      public void onerror(throwable e) {

      }

      @override
      public void onnext(object o) {

      }
    });

  }

 注:最后贴一个apk安装的方法

  // 安装apk
  public void installapk(string filepath) {
    intent intent = new intent();
    intent.setaction("android.intent.action.view");
    intent.addcategory("android.intent.category.default");
    intent.setflags(intent.flag_activity_new_task);// 广播里面操作需要加上这句,存在于一个独立的栈里
    intent.setdataandtype(uri.fromfile(new file(filepath)), "application/vnd.android.package-archive");
    mainactivity.startactivity(intent);
  }

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