基于Retrofit2+RxJava2实现Android App自动更新

本文实例为大家分享了Retrofit2 RxJava2实现Android App自动更新,具体内容如下

功能解析

自动更新可以说已经是App的标配了,很多第三方平台也都支持这个功能,最近手头上的项目需要加入这个App自动更新,考虑到项目里有用到Retrofit2和RxJava2,于是打算使用它俩自己实现这个功能。

分析App自动更新,可以分为以下三个功能点:

1.APK文件的下载
2.下载进度的实时更新显示
3.下载完成后的自动安装

其中比较难的一点是下载进度的实时更新显示,更难的是如何优雅的进行下载进度的更新显示,这也是为什么我用Retrofit2和RxJva2实现的原因。

用过Retrofit的人都知道他的内部是基于OkHttp实现的,OkHttp大家可能都不陌生,本次解决如何优雅的进行下载进度的更新显示的关键就在OkHttp的拦截器中,拦截器可谓是OKHttp的一大精髓,通过拦截器我们可以拿到Http的请求和响应信息,拿到了这些,你想干什么都行了。本次解决问题的核心就是在拦截器中拿到下载内容的长度并通过自定义的RxBus发送事件将下载信息发送出去,然后在合适的地方拿到这些下载信息,通过Notification实时展示下载进度。

先上一张App自动更新的流程图

功能实现

首先根据功能需求我创建了七个类:

1.ApiManager(Retrofit初始化和Api接口定义)
2.ApkLoadingBean(下载长度和文件总长度的数据类)
3.ApkResponseBody(自定义继承OKHttp的ResponseBody的类)重点
4.RxBus(使用RxJava实现的‘EventBus')重点
5.UpdateApkService(更新服务,在这里开启下载和订阅下载进度)重点
6.UpdateHelper(检查更新、弹出更新对话框)
7.UpdateManager(调用ApiManager接口进行下载)

先讲一下OKHttp里对拦截器的操作,我们在拦截器里拿到请求到的响应,对响应信息进行一些封装并通过RxBus发送出去。接下来看重点代码。

ApkResponseBody:

public class ApkResponseBody extends ResponseBody { 

 private Response originalResponse;//原responsebody 

 public ApkResponseBody(Response originalResponse) {
  this.originalResponse = originalResponse;
 } 

 /**
  * 返回内容类型
  *
  * @return
  */
 @Override
 public MediaType contentType() {
  return originalResponse.body().contentType();
 } 

 /**
  * 内容总长度
  * @return
  */
 @Override
 public long contentLength() {
  return originalResponse.body().contentLength();
 } 

 /**
  * 返回缓存源,类似于io中的BufferedReader
  *
  * @return
  */
 @Override
 public BufferedSource source() { 

  return Okio.buffer(new ForwardingSource(originalResponse.body().source()) {
   long totalRead = 0; 

   //返回读取的长度
   @Override
   public long read(Buffer sink, long byteCount) throws IOException {
    long bytesRead = super.read(sink, byteCount);
    totalRead += bytesRead == -1 ? 0 : bytesRead;
    Log.i("test", "本次下载:" + bytesRead);
    Log.i("test", "总共下载:" + totalRead);
    RxBus.getDefault().post(new ApkLoadingBean(contentLength(), totalRead));
    return bytesRead;
   } 

   @Override
   public Timeout timeout() {
    return super.timeout();
   } 

   @Override
   public void close() throws IOException {
    super.close();
   } 

   @Override
   public String toString() {
    return super.toString();
   }
  });
 }
} 

在source()方法中拿到下载长度和文件总长度,封装成Bean通过RxBus发送出去。并在ApiManager中初始化Retrofit的时候设置给OKHttp。

OkHttpClient client = new OkHttpClient().newBuilder()
    .addInterceptor(new Interceptor() {
     @Override
     public Response intercept(Chain chain) throws IOException {
      Response originalResponse = chain.proceed(chain.request());
      return originalResponse
        .newBuilder()
        .body(new ApkResponseBody(originalResponse))
        .build();
     }
    }).build(); 

RxBus:

public class RxBus { 

 private static volatile RxBus mInstance; 

 private final Subject<Object> mBus; 

 private RxBus() {
  this.mBus = PublishSubject.create().toSerialized();
 } 

 public static RxBus getDefault() {
  if (mInstance == null) {
   synchronized (RxBus.class) {
    if (mInstance == null) {
     mInstance = Holder.BUS;
    }
   }
  }
  return mInstance;
 } 

 /**
  * 发送一个事件
  *
  * @param obj
  */
 public void post(Object obj) {
  mBus.onNext(obj);
 } 

 /**
  * 暴露出RxBus的Observable供我们订阅事件
  *
  * @param tClass
  * @param <T>
  * @return
  */
 public <T> Observable<T> toObservable(Class<T> tClass) {
  return mBus.ofType(tClass);
 } 

 private static class Holder {
  private static final RxBus BUS = new RxBus();
 }
} 

UpdateService:

public class UpdateApkService extends IntentService { 

 private static Context mContext;
 public static final String ACTION_DOWNLOAD = "intentservice.ACTION_DOWNLOAD";
 public static final String DOWNLOAD_URL = "DOWNLOAD_URL";
 public static final String APK_PATH = "APK_PATH";
 private CompositeDisposable mCompositeDisposable = new CompositeDisposable();
 private NotificationCompat.Builder mBuilder;
 private NotificationManager mNotificationManager; 

 public UpdateApkService() {
  super("UpdateApkService");
 } 

 public static void startUpdateService(Context context, String url, String apkPath) {
  mContext = context;
  Intent intent = new Intent(context, UpdateApkService.class);
  intent.setPackage(context.getPackageName());
  intent.setAction(ACTION_DOWNLOAD);
  intent.putExtra(DOWNLOAD_URL, url);
  intent.putExtra(APK_PATH, apkPath);
  context.startService(intent);
 } 

 @Override
 protected void onHandleIntent(@Nullable Intent intent) {
  if (intent != null) {
   String action = intent.getAction();
   if (ACTION_DOWNLOAD.equals(action)) {
    T.showShort(mContext,"开始下载...");
    mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mBuilder = new NotificationCompat.Builder(this)
      .setSmallIcon(R.drawable.ic_launcher)
      .setContentTitle("下载最新版中")
      .setProgress(100, 0, false)
      .setAutoCancel(true);
    mNotificationManager.notify(0, mBuilder.build());
    String url = intent.getStringExtra(DOWNLOAD_URL);
    String apkPath = intent.getStringExtra(APK_PATH);
    subscribeEvent();//订阅下载进度
    UpdateManager.downLoadApk(this, url, apkPath, mCompositeDisposable);
   }
  }
 } 

 private void subscribeEvent() {
  RxBus.getDefault().toObservable(ApkLoadingBean.class)
    .subscribe(new Observer<ApkLoadingBean>() {
     @Override
     public void onSubscribe(Disposable d) {
      mCompositeDisposable.add(d);
     } 

     @Override
     public void onNext(ApkLoadingBean bean) {
      int progress = (int) Math.round(bean.getProgress() / (double) bean.getTotal() * 100);
      mBuilder.setProgress(100, progress, false);
      mNotificationManager.notify(0, mBuilder.build());
      if (progress==100)
       mNotificationManager.cancel(0);
     } 

     @Override
     public void onError(Throwable e) {
      subscribeEvent();
     } 

     @Override
     public void onComplete() {
      subscribeEvent();
     }
    });
 } 

 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.i("test", "UpdateService is destory");
 }
} 

在Service中订阅下载进度,拿到拦截器里发送的封装好的下载信息Bean,通过计算出进度显示在Notification上,这样就可以实现我们实时更新下载进度的需求了。

贴一张以上几个类的关联图,提大家梳理一下。

总结

通过Retrofit2+RxJava2实现了App自动更新,加深了我对这两个框架的理解和使用技巧,也扩展了自己的思路,记得以前自己写自动更新的时候,思绪混乱,代码不堪入目。。这次不仅实现了自动更新,还使用了相当优雅的解决方式。

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

您可能感兴趣的文章:

  • Android实现APP自动更新功能
  • Android应用APP自动更新功能的代码实现
  • Android如何实现APP自动更新
  • Android程序自动更新功能模块的实现方法【附完整demo源码下载】
  • Android应用自动更新功能实现的方法
  • Android App实现应用内部自动更新的最基本方法示例
  • Android编程实现应用自动更新、下载、安装的方法
  • Android 软件自动更新功能实现的方法
  • android实现通知栏下载更新app示例
  • android实现软件自动更新的步骤
(0)

相关推荐

  • android实现通知栏下载更新app示例

    1.设计思路,使用VersionCode定义为版本升级参数.android为我们定义版本提供了2个属性: 复制代码 代码如下: <manifest package="com.cnblogs.tianxia.subway"android:versionCode="1" <!--Integer类型,系统不显示给用户-->android:versionName="1.0"<!--String类型,系统显示用户-->>

  • Android如何实现APP自动更新

    先来看看要实现的效果图: 对于安卓用户来说,手机应用市场说满天飞可是一点都不夸张,比如小米,魅族,百度,360,机锋,应用宝等等,当我们想上线一款新版本APP时,先不说渠道打包的麻烦,单纯指上传APP到各大应用市场的工作量就已经很大了,好不容易我们把APP都上传完了,突然发现一个会导致应用闪退的小Bug,这时那个崩溃啊,明明不是很大的改动,难道我们还要再去重新去把各大应用市场的版本再上传更新一次?相信我,运营人员肯定会弄死你的!! 有问题,自然就会有解决问题的方案,因此我们就会想到如果在APP里

  • Android应用APP自动更新功能的代码实现

    由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必要给我们的Android应用增加自动更新的功能. 既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息: <update> <version>2</version> <name>baidu

  • Android实现APP自动更新功能

    现在一般的android软件都是需要不断更新的,当你打开某个app的时候,如果有新的版本,它会提示你有新版本需要更新.该小程序实现的就是这个功能. 该小程序的特点是,当有更新时,会弹出一个提示框,点击确定,则在通知来创建一个进度条进行下载,点击取消,则取消更新. 以下是详细代码: 1.创建布局文件notification_item.xml,用于在通知栏生成一个进度条和下载图标. <?xml version="1.0" encoding="utf-8"?>

  • Android App实现应用内部自动更新的最基本方法示例

    这只是初步的实现,并没有加入自动编译等功能.需要手动更改更新的xml文件和最新的apk.    共涉及到四个文件! 一.客户端 AndroidUpdateTestActivity:程序首页 main.xml:首页布局 Update:更新类 softupdate_progress:更新等待界面 Updage package majier.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOExce

  • Android应用自动更新功能实现的方法

    本文给大家分享Android里应用版本更新功能这一块的实现. 一个好的应用软件都是需要好的维护,从初出版本到最后精品,这个过程需要版本不停的更新,那么如何让用户第一时间获取最新的应用安装包呢?那么就要求我们从第一个版本就要实现升级模块这一功能. 自动更新功能的实现原理,就是我们事先和后台协商好一个接口,我们在应用的主Activity里,去访问这个接口,如果需要更新,后台会返回一些数据(比如,提示语:最新版本的url等).然后我们给出提示框,用户点击开始下载,下载完成开始覆盖安装程序,这样用户的应

  • Android程序自动更新功能模块的实现方法【附完整demo源码下载】

    本文实例讲述了Android程序自动更新功能模块的实现方法.分享给大家供大家参考,具体如下: 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新. 在程序启动的时候首先调用更新模块检测服务器上存放的版本号跟当前程序的版本号如果大于当前版本号,弹出更新对话框,如果用户选择更新,则显示当前更新状态,然后替换当前程序. 程序调用版本更新检测: private UpdateManager updateMan; private ProgressDialog updateProgr

  • Android 软件自动更新功能实现的方法

    相信所有的用户都遇到过软件提醒更新的情况,下面就将实现此功能 首先看一下程序目录结构    步骤: 1.新建一个类UpdateManger,用于显示提示更新 复制代码 代码如下: public class UpdateManger { // 应用程序Context private Context mContext; // 提示消息 private String updateMsg = "有最新的软件包,请下载!"; // 下载安装包的网络路径 private String apkUrl

  • Android编程实现应用自动更新、下载、安装的方法

    本文实例讲述了Android编程实现应用自动更新.下载.安装的方法.分享给大家供大家参考,具体如下: 我们看到很多Android应用都具有自动更新功能,用户一键就可以完成软件的升级更新.得益于Android系统的软件包管理和安装机制,这一功能实现起来相当简单,下面我们就来实践一下. 1. 准备知识 在AndroidManifest.xml里定义了每个Android apk的版本标识: <manifest xmlns:android="http://schemas.android.com/a

  • android实现软件自动更新的步骤

    本篇文章是直接下载最新的APK安装的方法,并不是增量下载该APk. 想要实现一个android应用,自动更新下载APK软件的方法,我采取的是以下几步方法: 1.每次进入主界面时,获取服务器的数据,看是否是最新版本,是,则无操作,否,则进行以下步骤: 2.弹出是否更新软件的对话框,点击下载后 3.弹出下载的进度条的对话框,开始下载,可以上随时点击按钮,停止下载 4.下载完成后,调用系统安装软件的服务,安装软件 效果图:     实现过程:   新建一个UpdateManager方法,具体内容我已经

随机推荐