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

作者:Ever69 时间:2021-09-04 20:19:29 

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

功能解析

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

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

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

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

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

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

基于Retrofit2+RxJava2实现Android 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实现Android App自动更新

总结

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

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

来源:https://blog.csdn.net/Ever69/article/details/80222543

标签:Android,App,自动更新
0
投稿

猜你喜欢

  • Android Support Palette使用详解

    2023-04-05 15:47:24
  • 谈一谈Android内存泄漏问题

    2023-01-29 23:23:54
  • Winform 控件优化LayeredWindow无锯齿圆角窗体

    2021-12-07 22:54:17
  • cmd中javac和java使用及注意事项详解

    2022-03-25 10:37:36
  • java8 集合 多字段 分组 统计个数代码

    2022-12-07 21:03:34
  • Android XRecyclerView实现多条目加载

    2021-10-15 07:32:21
  • Java用for循环Map详细解析

    2021-06-08 08:23:03
  • Java内部类及其特点的讲解

    2023-06-09 19:39:41
  • Android 添加TextView删除线(代码简单)

    2022-05-27 16:48:47
  • java 实现将Object类型转换为int类型

    2023-11-11 07:58:03
  • Spring超详细讲解IOC与解耦合

    2023-06-16 12:32:50
  • 使用java生成json时产生栈溢出错误问题及解决方案

    2023-01-09 17:41:10
  • Android开发flow常见API的使用示例详解

    2021-09-25 05:27:49
  • Java自定义实现equals()方法过程解析

    2021-10-12 11:21:48
  • Java中EasyPoi多sheet导出功能实现

    2023-01-15 08:10:39
  • Android 开发使用PopupWindow实现加载等待界面功能示例

    2023-03-26 07:51:36
  • Android Service启动过程完整分析

    2021-11-25 11:02:44
  • 一问详解SpringBoot配置文件优先级

    2023-01-08 05:40:14
  • Java中关于二叉树的概念以及搜索二叉树详解

    2023-01-12 00:09:25
  • 使用JSONObject生成和解析json的方法

    2022-06-15 11:13:15
  • asp之家 软件编程 m.aspxhome.com