一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 初尝黑人巨大h文 | 日本三级做a全过程在线观看 | 国产成人精品本亚洲 | 成年人免费在线看 | 第一国内永久免费福利视频 | 亚洲性视频在线观看 | 午夜电影三级还珠格格 | 国产成人一区二区三区在线视频 | 色老头综合网 | 国产精品秒播无毒不卡 | 免费a视频在线观看 | 高清一区 | bbc japanese黑人强行 | 天天成人 | 欧美高清一级 | 99热这里有精品 | 手机看片福利盒子久久 | 精品国产欧美一区二区三区成人 | 香蕉国产人午夜视频在线 | 欧美日韩国产另类一区二区三区 | 古代双性美人被老糟蹋 | 91在线高清视频 | 亚洲高清国产拍精品动图 | 国产色资源 | 国产成人精品高清免费 | 久草热8精品视频在线观看 久草草在线视视频 | 欧美破苞合集 magnet | 2021日本三级理论影院 | 国产不卡视频一区二区在线观看 | 色帝国亚洲欧美在线蜜汁tv | 男生操女生的漫画 | 亚洲精品国产成人99久久 | 午夜电影三级还珠格格 | 王晶三级作品 | 欧洲美女啪啪 | 99热这里只有精品国产免费 | 顶级尤物极品女神福利视频 | 极品一区| 色在线看| 青青自拍视频 | 亚洲天堂精品在线 |