服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - 基于Retrofit2+RxJava2实现Android App自动更新

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

2022-02-16 16:19Ever69 Android

这篇文章主要为大家详细介绍了基于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自动更新的流程图

基于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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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。

?
1
2
3
4
5
6
7
8
9
10
11
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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

延伸 · 阅读

精彩推荐
  • AndroidAndroid程序设计之AIDL实例详解

    Android程序设计之AIDL实例详解

    这篇文章主要介绍了Android程序设计的AIDL,以一个完整实例的形式较为详细的讲述了AIDL的原理及实现方法,需要的朋友可以参考下...

    Android开发网4642021-03-09
  • AndroidAndroid实现Service获取当前位置(GPS+基站)的方法

    Android实现Service获取当前位置(GPS+基站)的方法

    这篇文章主要介绍了Android实现Service获取当前位置(GPS+基站)的方法,较为详细的分析了Service基于GPS位置的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    Ruthless8342021-03-31
  • AndroidAndroid CardView+ViewPager实现ViewPager翻页动画的方法

    Android CardView+ViewPager实现ViewPager翻页动画的方法

    本篇文章主要介绍了Android CardView+ViewPager实现ViewPager翻页动画的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Abby代黎明9602022-03-02
  • AndroidAndroid实现固定屏幕显示的方法

    Android实现固定屏幕显示的方法

    这篇文章主要介绍了Android实现固定屏幕显示的方法,实例分析了Android屏幕固定显示所涉及的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    鉴客6192021-03-27
  • AndroidAndroid中AsyncTask详细介绍

    Android中AsyncTask详细介绍

    这篇文章主要介绍了Android中AsyncTask详细介绍,AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合,需要的朋友可以参考下...

    Android开发网7452021-03-11
  • AndroidAndroid界面效果UI开发资料汇总(附资料包)

    Android界面效果UI开发资料汇总(附资料包)

    android ui界面设计,友好的界面会提高用户体验度;同时也增强了android ui界面设计的难度,本文提供了一些常用开发资料(有下载哦)感兴趣的朋友可以了解下...

    Android开发网4672021-01-03
  • Android汇总Android视频录制中常见问题

    汇总Android视频录制中常见问题

    这篇文章主要汇总了Android视频录制中常见问题,帮助大家更好地解决Android视频录制中常见的问题,需要的朋友可以参考下...

    yh_thu5192021-04-28
  • AndroidAndroid编程解析XML方法详解(SAX,DOM与PULL)

    Android编程解析XML方法详解(SAX,DOM与PULL)

    这篇文章主要介绍了Android编程解析XML方法,结合实例形式详细分析了Android解析XML文件的常用方法与相关实现技巧,需要的朋友可以参考下...

    liuhe68810052021-05-03