Retrofit+RxJava实现带进度条的文件下载

项目中需要使用到更新版本,因此研究了一下Retrofit的下载文件,和进度条效果,其间也遇到了一些坑,写出来加深一下记忆,也为别的同学提供一下思路。

先说一下版本控制吧,通用做法基本上是通过接口获取服务器存储的app版本号,与应用的版本号进行比较,版本较低就去更新,先看一下如何获取应用版本号吧

PackageManager packageManager = mActivity.getPackageManager();

  PackageInfo packageInfo = null;

  try {
   packageInfo = packageManager.getPackageInfo(mActivity.getPackageName(), 0);
  } catch (PackageManager.NameNotFoundException e) {
   e.printStackTrace();
  }

  String versionName = packageInfo.versionName;

可以看到使用的是Context中的getPackageManager方法来获取PackageManager 对象,该对象可用于获取版本的一些信息。

上面的属于附内容,接下来就是关于Retrofit+RxJava实现进度条下载文件的功能,Retrofit本身不提供进度条显示的功能,但Retrofit默认使用Okhttp来进行网络请求,这里就可以自定义拦截器来进行拦截,实现进度。Okhttp的Demo中也为我们提供了一份代码,需要的可以去参考一下Progress.javar,可以看到拦截器的设置:

public class ProgressResponseBody extends ResponseBody {

 private ResponseBody responseBody;

 private ProgressListener progressListener;

 private BufferedSource bufferedSource;

 public ProgressResponseBody(ResponseBody responseBody,ProgressListener progressListener){

  this.responseBody=responseBody;

  this.progressListener=progressListener;
 }

 @Override
 public MediaType contentType() {

  return responseBody.contentType();
 }

 @Override
 public long contentLength() {

  return responseBody.contentLength();
 }

 @Override
 public BufferedSource source() {

  if(bufferedSource==null){

   bufferedSource= Okio.buffer(source(responseBody.source()));
  }

  return bufferedSource;
 }

 private Source source(Source source) {
  return new ForwardingSource(source) {
   long totalBytesRead = 0L;

   @Override
   public long read(Buffer sink, long byteCount) throws IOException {
    //当前读取字节数
    long bytesRead = super.read(sink, byteCount);
    //增加当前读取的字节数,如果读取完成了bytesRead会返回-1
    totalBytesRead += bytesRead != -1 ? bytesRead : 0;
    //回调,如果contentLength()不知道长度,会返回-1

   progressListener.onProgress(totalBytesRead,responseBody.contentLength(),bytesRead,bytesRead==-1);
    return bytesRead;
   }
  };
 }
}

ProgressListener 用来监听进度变化,回调到ProgressInterceptor中,ProgressInterceptor是一个自定义的拦截器,可以看一下代码

public class ProgressInterceptor implements Interceptor {

 @Override
 public Response intercept(Chain chain) throws IOException {

  Response response=chain.proceed(chain.request());
  return response.newBuilder().body(new ProgressResponseBody(response.body(),progressListener)).build();
 }
 static final ProgressListener progressListener=new ProgressListener() {
  @Override
  public void onProgress(long progress, long total, long speed, boolean done) {

   Log.i("log","progress="+progress+"total="+total);
  }
 };
}

为了便于获取progress,可以通过OkHttpClient的addNetworkInterceptor方法直接添加一个自定义的拦截器,例如:

 //为Okhttp设置拦截器
 OkHttpClient client = new OkHttpClient.Builder()
   .addNetworkInterceptor(new Interceptor() {
    @Override public Response intercept(Chain chain) throws IOException {
     Response originalResponse = chain.proceed(chain.request());
     return originalResponse.newBuilder()
       .body(new ProgressResponseBody(originalResponse.body(), progressListener))
       .build();
    }
   })
   .build();

 //进度回调监听
 ProgressListener progressListener=new ProgressListener() {
  @Override
  public void onProgress(long progress, long total, long speed, boolean done) {

   Message message=new Message();

   message.obj=new AmallLoadBean(progress,total);

   progressHandler.sendMessage(message);
  }
 };

这里通过一个创建一个继承自Handler的ProgressHandler静态内部类用于在主线程中刷新进度,顺带提一下,使用static修饰ProgressHandler是因为静态内部类默认不持有外部类对象的引用,需要注意一下Handler的内存泄漏,使用一下写法:

//处理下载版本进度
 public class ProgressHandler extends Handler{

  private WeakReference<Activity> mActivityWeakReference;
  public ProgressHandler(Activity activity){

   mActivityWeakReference=new WeakReference<Activity>(activity);

  }

  @Override
  public void handleMessage(Message msg) {
   if(mActivityWeakReference.get()!=null){
    AmallLoadBean amallLoadBean= (AmallLoadBean) msg.obj;
    long progress=amallLoadBean.getProgress();
    long total=amallLoadBean.getTotal();
    float cp=(float)progress/(float)total;

   }
  }
 }

继续回到下载文件中,我才用的是Retrofit+RxJava的方法来实现,写之前也看了一下别人写的,好像不全,下满也遇到了一些小坑,讲一下吧:

observable.subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .doOnNext(new Action1<ResponseBody>() {
     @Override
     public void call(ResponseBody responseBody) {

      saveFiles(responseBody);
     }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<ResponseBody>() {
     @Override
     public void onCompleted() {
      installApk();

     }

     @Override
     public void onError(Throwable e) {

      ToastUtils.getInstance().showToast("请到应用市场下载最新版本");
     }

     @Override
     public void onNext(ResponseBody responseBody) {

     }
    });
 }

通过RxJava的doOnNext在subscribe方法之前存储文件,这里需要注意的是doOnNext方法需要在子线程中执行,调用.observeOn(Schedulers.io())方法,然后再切换到主线程,否则文件下载不下来。当文件下载完成时,在onCompleted方法中执行installApk()方法安装app。需要注意的是这里需要做权限的适配,因为我的是自己封装的因为就不拿出来了,挺简单就自己写吧。保存文件的代码给大家放出来了,通俗的语言:

/**
 * 保存文件
 */
 public void saveFiles(ResponseBody responseBody){

  InputStream inputStream = null;

  FileOutputStream fileOutputStream = null;

  byte[] buffer=new byte[2048];

  int len;

  File file=new File(saveFileName);

  if(!file.exists()){

   file.mkdirs();
  }

  try {
   inputStream=responseBody.byteStream();

   fileOutputStream=new FileOutputStream(file);

   while ((len=inputStream.read(buffer))!=-1){

    fileOutputStream.write(buffer,0,len);
   }

   inputStream.close();

   fileOutputStream.close();

  } catch (Exception e) {
   e.printStackTrace();
  }

 }

在安装文件的时候,需要注意7.0以后的适配,代码看看就好,和拍照适配的原理一直,都是Android对私密性文件的权限问题

 /**
  * 安装apk
  *
  */
 private void installApk() {
  File apkfile = new File(saveFileName);
  if (!apkfile.exists()) {
   return;
  }
  //判断版本号

  if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
   Uri apkUri = FileProvider.getUriForFile(activity, "******.fileprovider", apkfile);
   Intent install = new Intent(Intent.ACTION_VIEW);
   install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   //添加这一句表示对目标应用临时授权该Uri所代表的文件
   install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
   install.setDataAndType(apkUri, "application/vnd.android.package-archive");
   activity.startActivity(install);

  }else{

   Intent i = new Intent(Intent.ACTION_VIEW);
   i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
   activity.startActivity(i);
  }

 }

基本上就这些,后续我会在此篇文章上继续补充。

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

(0)

相关推荐

  • 基于Ok+Rxjava+retrofit实现断点续传下载

    本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下 1.基于Ok+Rxjava实现断点续传下载 2.基于Ok+Rxjava+Retrofit实现断点续传下载 上一篇博客中介绍了基于Ok+Rxjava实现断点续传下载,这一篇给大家介绍下基于Ok+Rxjava+Retrofit实现断点续传下载,demo下载地址,效果图跟上一篇图片一样,哈哈 说下我的大致思路吧(跟上一篇略有不同):根据文件下载url按照自己定义的规则生成文件名,判断本地同路径下是否存在此文件,如果存在,文件大小与服

  • Retrofit+Rxjava实现文件上传和下载功能

    Retrofit简介: 在Android API4.4之后,Google官方使用了square公司推出的okHttp替换了HttpClient的请求方式.后来square公司又推出了基于okHttp的网络请求框架:Retrofit. 什么是 RxJava? RxJava 是一个响应式编程框架,采用观察者设计模式.所以自然少不了 Observable 和 Subscriber 这两个东东了. RxJava 是一个开源项目,地址:https://github.com/ReactiveX/RxJava

  • RxJava+Retrofit+OkHttp实现多文件下载之断点续传

    背景 断点续传下载一直是移动开发中必不可少的一项重要的技术,同样的Rxjava和Retrofit的结合让这个技术解决起来更加的灵活,我们完全可以封装一个适合自的下载框架,简单而且安全! 效果 实现 下载和之前的http请求可以相互独立,所以我们单独给download建立一个工程moudel处理 1.创建service接口 和以前一样,先写接口 注意:Streaming是判断是否写入内存的标示,如果小文件可以考虑不写,一般情况必须写:下载地址需要通过@url动态指定(不适固定的),@head标签是

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

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

  • Retrofit+RxJava实现带进度下载文件

    Retrofit+RxJava已经是目前市场上最主流的网络框架,使用它进行平常的网络请求异常轻松,之前也用Retrofit做过上传文件和下载文件,但发现:使用Retrofit做下载默认是不支持进度回调的,但产品大大要求下载文件时显示下载进度,那就不得不深究下了. 接下来我们一起封装,使用Retrofit+RxJava实现带进度下载文件. github:JsDownload 先来看看UML图: 大家可能还不太清楚具体是怎么处理的,别急,我们一步步来: 1.添依赖是必须的啦 compile 'io.

  • Retrofit Rxjava实现图片下载、保存并展示实例

    首先我们看一下Retrofit常规的用法,在不使用Rxjava的情况下,我们默认返回的是Call. public interface ServiceApi { //下载文件 @GET Call<ResponseBody> downloadPicFromNet(@Url String fileUrl); } 但是如果我们要配合Rxjava使用,那么就要按照如下方式来重新定义我们的方法: @GET Observable<ResponseBody> downloadPicFromNet(

  • 基于Retrofit+Rxjava实现带进度显示的下载文件

    本文实例为大家分享了Retrofit Rxjava实现下载文件的具体代码,供大家参考,具体内容如下 本文采用 :retrofit + rxjava 1.引入: //rxJava compile 'io.reactivex:rxjava:latest.release' compile 'io.reactivex:rxandroid:latest.release' //network - squareup compile 'com.squareup.retrofit2:retrofit:latest

  • Retrofit+Rxjava下载文件进度的实现

    前言 最近在学习Retrofit,虽然Retrofit没有提供文件下载进度的回调,但是Retrofit底层依赖的是OkHttp,实际上所需要的实现OkHttp对下载进度的监听,在OkHttp的官方Demo中,有一个Progress.java的文件,顾名思义.点我查看. 准备工作 本文采用Dagger2,Retrofit,RxJava. compile'com.squareup.retrofit2:retrofit:2.0.2' compile'com.squareup.retrofit2:con

  • Retrofit+RxJava实现带进度条的文件下载

    项目中需要使用到更新版本,因此研究了一下Retrofit的下载文件,和进度条效果,其间也遇到了一些坑,写出来加深一下记忆,也为别的同学提供一下思路. 先说一下版本控制吧,通用做法基本上是通过接口获取服务器存储的app版本号,与应用的版本号进行比较,版本较低就去更新,先看一下如何获取应用版本号吧 PackageManager packageManager = mActivity.getPackageManager(); PackageInfo packageInfo = null; try { p

  • Android编程开发实现带进度条和百分比的多线程下载

    本文实例讲述了Android编程开发实现带进度条和百分比的多线程下载.分享给大家供大家参考,具体如下: 继上一篇<java多线程下载实例详解>之后,可以将它移植到我们的安卓中来,下面是具体实现源码: DownActivity.java: package com.example.downloads; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.H

  • android中实现OkHttp下载文件并带进度条

    OkHttp是比较火的网络框架,它支持同步与异步请求,支持缓存,可以拦截,更方便下载大文件与上传文件的操作.下面我们用OkHttp来下载文件并带进度条! 相关资料: 官网地址:http://square.github.io/okhttp/ github源码地址:https://github.com/square/okhttp 一.服务器端简单搭建 可以参考搭建本地Tomcat服务器及相关配置这篇文章. 新建项目OkHttpServer,在WebContent目录下新建downloadfile目录

  • jQuery上传多张图片带进度条样式(DEMO)

    下面一段代码给大家分享jquery上传多种图片带进度条样式,具体代码如下所示: <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>xhr2</title> </head> <body> <div style="text-align: center; margin: 100px"> <

  • springMVC实现前台带进度条文件上传的示例代码

    项目框架采用spring+hibernate+springMVC如果上传文件不想使用flash那么你可以采用HTML5;截图前段模块是bootstarp框架;不废话直接来代码;spring-mvc配置文件;效果截图如下: 详细实现如下: 1.mvc-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/s

  • asp.net mvc 实现文件上传带进度条的思路与方法

    前言 文件上传与下载的操作在实际项目中经常是很重要的一个内容,在使用ASP.NET Web Form的时候我们可以使用诸多的服务器控件,FileIpload就是其中之一,但是在ASP.NET不建议使用那些服务器控件,因为那样违反三层架构原则.最近参考网络资料,学习了ASP.NET MVC如何上传文件. 而这篇文章主要重点是asp.net mvc 实现文件上传带进度条,下面来一起看看吧. 实现思路 ajax异步上传文件,且开始上传文件的时候启动轮询来实时获取文件上传进度.保存进度我采用的是memc

  • asp.net单文件带进度条上传的解决方案

    最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的ASP.NET实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序. 首先看下界面效果,当然你可以完全修改界面为你自己所用. 先解释一下这个程序,该程序采用了jquery框架,实现了小文件上传,不超过80Mb,可以在web.config文件中进行相应的配置,但是有个最大值,具体需要查看msdn.开发环境采用visual studio 2013 .net framework 4.5,运行的时候

  • asp.net文件上传带进度条实现案例(多种风格)

    先饱饱眼福: 在之前的文章中也有类似带进度条文件传送的案例,大家可以翻阅之前的文章对知识点进行扩充. 部分代码: <%@ Page Language="C#" %> <%@ Register Assembly="MattBerseth.WebControls.AJAX" Namespace="MattBerseth.WebControls.AJAX.Progress" TagPrefix="mb" %>

随机推荐