基于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自动更新的流程图

img

功能实现

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

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上,这样就可以实现我们实时更新下载进度的需求了。

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

img

总结

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

img

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

更多Android进阶指南 可以扫码 解锁 《Android十大板块文档》

1.Android车载应用开发系统学习指南(附项目实战)

2.Android Framework学习指南,助力成为系统级开发高手

3.2023最新Android中高级面试题汇总+解析,告别零offer

4.企业级Android音视频开发学习路线+项目实战(附源码)

5.Android Jetpack从入门到精通,构建高质量UI界面

6.Flutter技术解析与实战,跨平台首要之选

7.Kotlin从入门到实战,全方面提升架构基础

8.高级Android插件化与组件化(含实战教程和源码)

9.Android 性能优化实战+360°全方面性能调优

10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 开发中,可以使用 OkHttp 作为网络请求框架、RxJava 作为异步处理框架、Retrofit 作为接口封装框架,来实现网络请求的快速开发。以下是一个基于 OkHttp+RxJava+Retrofit 的网络请求工具类的代码示例: 1. 添加依赖 在 app 模块的 build.gradle 文件中添加以下依赖: ``` implementation 'com.squareup.okhttp3:okhttp:x.x.x' implementation 'io.reactivex.rxjava2:rxjava:x.x.x' implementation 'io.reactivex.rxjava2:rxandroid:x.x.x' implementation 'com.squareup.retrofit2:retrofit:x.x.x' implementation 'com.squareup.retrofit2:converter-gson:x.x.x' ``` 其中,x.x.x 为最新版本号。 2. 创建 RetrofitService 接口 可以创建一个 RetrofitService 接口,通过注解的方式定义网络请求接口。例如: ```java public interface RetrofitService { // 定义 GET 请求接口 @GET("api/data/{category}/{count}/{page}") Observable<GankResult<List<GankItem>>> getGankList( @Path("category") String category, @Path("count") int count, @Path("page") int page ); } ``` 其中,GankResult 和 GankItem 是自定义的类,用于接收服务器返回的数据。 3. 创建 Retrofit 实例 可以创建一个 Retrofit 实例,通过 baseUrl 和 converterFactory 参数配置 Retrofit 实例。例如: ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .build(); ``` 其中,GsonConverterFactory 用于将服务器返回的 JSON 格式数据转换为 Java 对象,RxJava2CallAdapterFactory 用于将 Retrofit 的 Call 对象转换为 RxJava 的 Observable 对象,okHttpClient 是一个 OkHttp 的 OkHttpClient 对象,用于配置网络请求参数。 4. 创建 OkHttp 实例 可以创建一个 OkHttp 实例,通过 builder 模式配置网络请求参数。例如: ```java OkHttpClient okHttpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .addInterceptor(interceptor) .build(); ``` 其中,connectTimeout、readTimeout 和 writeTimeout 用于设置连接、读取和写入超时时间,interceptor 是一个 OkHttp 的 Interceptor 对象,用于拦截网络请求和响应。 5. 创建网络请求工具类 可以创建一个网络请求工具类,通过 Retrofit 实例创建 RetrofitService 对象,并通过 RxJava 实现异步网络请求。例如: ```java public class HttpUtil { private RetrofitService retrofitService; public HttpUtil() { // 创建 OkHttp 实例 OkHttpClient okHttpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) .build(); // 创建 Retrofit 实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .build(); // 创建 RetrofitService 接口实例 retrofitService = retrofit.create(RetrofitService.class); } // GET 请求 public Observable<GankResult<List<GankItem>>> getGankList(String category, int count, int page) { return retrofitService.getGankList(category, count, page); } } ``` 其中,HttpUtil 类使用了单例模式,通过 RetrofitService 接口实例实现网络请求。 6. 使用网络请求工具类 可以在 Activity 或 Fragment 中使用网络请求工具类,通过 RxJava 实现异步网络请求。例如: ```java public class MainActivity extends AppCompatActivity { private HttpUtil httpUtil; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 创建 HttpUtil 实例 httpUtil = new HttpUtil(); // 发起 GET 请求 httpUtil.getGankList("Android", 10, 1) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<GankResult<List<GankItem>>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(GankResult<List<GankItem>> gankResult) { // 处理网络请求结果 } @Override public void onError(Throwable e) { // 处理网络请求错误 } @Override public void onComplete() { } }); } } ``` 其中,subscribeOn() 方法用于指定网络请求在 IO 线程中执行,observeOn() 方法用于指定网络请求结果在主线程中回调。 总之,以上是一个基于 OkHttp+RxJava+Retrofit 的网络请求工具类的代码示例,可以根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值