(一)Rxjava2+Retrofit完美封装

(一)Rxjava2+Retrofit完美封装本篇文章已授权微信公众号 guolin blog 郭霖 独家发布要说 2016 年最火的 Android 技术是什么 毫无疑问肯定是 RxJava Retrofit Mvp 现如今 2017 年也已经过了快一半了 相信做 android 开发的小伙伴对 RxJava 和 Retrofit 也不再陌生 即使没有刻意的去学习过 也应该对 RxJava 和 Retrofit 有个一知半解 去年的时候学习了 Rxjava 和 Retr

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

RetrofitHelper.getApiService() .getArticle() .compose(RxUtil.<ArticleWrapper>rxSchedulerHelper(this)) .subscribe(new DefaultObserver<ArticleWrapper>() { @Override public void onSuccess(ArticleWrapper response) { showToast("Request Success,size is:" + response.getDatas().size()); } }); 
 compile "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version" compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:converter-scalars:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.ext.retrofit2Version" compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' compile "com.trello.rxlifecycle2:rxlifecycle:$rootProject.ext.rxlifecycle" //compile "com.trello.rxlifecycle2:rxlifecycle-android:$rootProject.ext.rxlifecycle" compile "com.trello.rxlifecycle2:rxlifecycle-components:$rootProject.ext.rxlifecycle" 

为了方便依赖库版本的修改我们采用”io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version”这中方式添加依赖,因此需要在project的build.gradle文件的加上以下内容:

ext { supportLibVersion = '25.1.0' butterknifeVersion = '8.5.1' rxjava2Version = '2.0.8' retrofit2Version = '2.2.0' rxlifecycle='2.1.0' gsonVersion = '2.8.0' } 

下面将通过几个小节对本次封装作详细的解析:

  • 服务器响应数据的基类BasicResponse
  • 构建初始化Retrofit的工具类IdeaApi
  • 通过GsonConverterFactory获取真实响应数据
  • 封装DefaultObserver处理服务器响应
  • 处理加载Loading
  • 管理Retrofit生命周期
  • 如何使用封装
  • 小结

一.服务器响应数据的基类BasicResponse。

假定服务器返回的Json数据格式如下:

{ "code": 200, "message": "成功", "content": { ... } } 

根据Json数据格式构建我们的BasicResponse(BasicResponse中的字段内容需要根据自己服务器返回的数据确定)。代码如下:

public class BasicResponse<T> { private int code; private String message; private T content; ...此处省去get、set方法。 

二.构建初始化Retrofit的工具类IdeaApi。

该类通过RetrofitUtils来获取ApiService的实例。代码如下:

public class IdeaApi { public static <T> T getApiService(Class<T> cls,String baseUrl) { Retrofit retrofit = RetrofitUtils .getRetrofitBuilder(baseUrl).build(); return retrofit.create(cls); } } 

RetrofitUtils用来构建Retrofit.Builder,并对OkHttp做以下几个方面的配置:

  1. 设置日志拦截器,拦截服务器返回的json数据。Retrofit将请求到json数据直接转换成了实体类,但有时候我们需要查看json数据,Retrofit并没有提供直接获取json数据的功能。因此我们需要自定义一个日志拦截器拦截json数据,并输入到控制台。
  2. 设置Http请求头。给OkHttp 添加请求头拦截器,配置请求头信息。还可以为接口统一添加请求头数据。例如,把用户名、密码(或者token)统一添加到请求头。后续每个接口的请求头中都会携带用户名、密码(或者token)数据,避免了为每个接口单独添加。
  3. 为OkHttp配置缓存。同样可以同过拦截器实现缓存处理。包括控制缓存的最大生命值,控制缓存的过期时间。
  4. 如果采用https,我们还可以在此处理证书校验以及服务器校验。
  5. 为Retrofit添加GsonConverterFactory。此处是一个比较重要的环节,将在后边详细讲解。
    RetrofitUtils 代码如下:
public class RetrofitUtils { public static OkHttpClient.Builder getOkHttpClientBuilder() { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { try { LogUtils.e("OKHttp-----", URLDecoder.decode(message, "utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); LogUtils.e("OKHttp-----", message); } } }); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); File cacheFile = new File(Utils.getContext().getCacheDir(), "cache"); Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb return new OkHttpClient.Builder() .readTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) .connectTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) .addInterceptor(loggingInterceptor) .addInterceptor(new HttpHeaderInterceptor()) .addNetworkInterceptor(new HttpCacheInterceptor()) // .sslSocketFactory(SslContextFactory.getSSLSocketFactoryForTwoWay()) // https认证 如果要使用https且为自定义证书 可以去掉这两行注释,并自行配制证书。 // .hostnameVerifier(new SafeHostnameVerifier()) .cache(cache); } public static Retrofit.Builder getRetrofitBuilder(String baseUrl) { Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create(); OkHttpClient okHttpClient = RetrofitUtils.getOkHttpClientBuilder().build(); return new Retrofit.Builder() .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl(baseUrl); } } 

三.通过GsonConverterFactory获取真实响应数据

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> { private final TypeAdapter<T> adapter; GsonResponseBodyConverter(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public Object convert(ResponseBody value) throws IOException { try { BasicResponse response = (BasicResponse) adapter.fromJson(value.charStream()); if (response.getCode()==200) { return response.getResults(); } else { // 特定 API 的错误,在相应的 DefaultObserver 的 onError 的方法中进行处理 throw new ServerResponseException(response.getCode(), response.getMessage()); } } finally { value.close(); } return null; } } 

四.构建DefaultObserver处理服务器响应。

public abstract class DefaultObserver<T> implements Observer<T> { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(T response) { onSuccess(response); onFinish(); } @Override public void onError(Throwable e) { LogUtils.e("Retrofit", e.getMessage()); if (e instanceof HttpException) { // HTTP错误 onException(ExceptionReason.BAD_NETWORK); } else if (e instanceof ConnectException || e instanceof UnknownHostException) { // 连接错误 onException(ExceptionReason.CONNECT_ERROR); } else if (e instanceof InterruptedIOException) { // 连接超时 onException(ExceptionReason.CONNECT_TIMEOUT); } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) { // 解析错误 onException(ExceptionReason.PARSE_ERROR); }else if(e instanceof ServerResponseException){ onFail(e.getMessage()); } else { onException(ExceptionReason.UNKNOWN_ERROR); } onFinish(); } @Override public void onComplete() { } / * 请求成功 * * @param response 服务器返回的数据 */ abstract public void onSuccess(T response); / * 服务器返回数据,但响应码不为200 * */ public void onFail(String message) { ToastUtils.show(message); } public void onFinish(){} / * 请求异常 * * @param reason */ public void onException(ExceptionReason reason) { switch (reason) { case CONNECT_ERROR: ToastUtils.show(R.string.connect_error, Toast.LENGTH_SHORT); break; case CONNECT_TIMEOUT: ToastUtils.show(R.string.connect_timeout, Toast.LENGTH_SHORT); break; case BAD_NETWORK: ToastUtils.show(R.string.bad_network, Toast.LENGTH_SHORT); break; case PARSE_ERROR: ToastUtils.show(R.string.parse_error, Toast.LENGTH_SHORT); break; case UNKNOWN_ERROR: default: ToastUtils.show(R.string.unknown_error, Toast.LENGTH_SHORT); break; } } / * 请求网络失败原因 */ public enum ExceptionReason { / * 解析数据失败 */ PARSE_ERROR, / * 网络问题 */ BAD_NETWORK, / * 连接错误 */ CONNECT_ERROR, / * 连接超时 */ CONNECT_TIMEOUT, / * 未知错误 */ UNKNOWN_ERROR, } } 

五.处理加载Loading

public class ProgressUtils { public static <T> ObservableTransformer<T, T> applyProgressBar( @NonNull final Activity activity, String msg) { final WeakReference<Activity> activityWeakReference = new WeakReference<>(activity); final DialogUtils dialogUtils = new DialogUtils(); dialogUtils.showProgress(activityWeakReference.get()); return new ObservableTransformer<T, T>() { @Override public ObservableSource<T> apply(Observable<T> upstream) { return upstream.doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(Disposable disposable) throws Exception { } }).doOnTerminate(new Action() { @Override public void run() throws Exception { Activity context; if ((context = activityWeakReference.get()) != null && !context.isFinishing()) { dialogUtils.dismissProgress(); } } }).doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(Disposable disposable) throws Exception { /*Activity context; if ((context = activityWeakReference.get()) != null && !context.isFinishing()) { dialogUtils.dismissProgress(); }*/ } }); } }; } public static <T> ObservableTransformer<T, T> applyProgressBar( @NonNull final Activity activity) { return applyProgressBar(activity, ""); } } 

至此关于RxJava和Retrofit的二次封装已经基本完成。但是我们不能忽略了很重要的一点,就是网络请求的生命周期。我们将在下一节中详细讲解。

六、管理Retrofit生命周期

当activity被销毁时,网络请求也应该随之终止的。要不然就可能造成内存泄漏。会严重影到响App的性能!因此Retrofit生命周期的管理也是比较重要的一点内容。在这里我们使用 RxLifecycle来对Retrofit进行生命周期管理。其使用流程如下:

1.在gradel中添加依赖如下:

compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0' compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' 

2.让我们的BaseActivity继承RxAppCompatActivity。
具体代码如下:

public abstract class BaseActivity extends RxAppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); init(savedInstanceState); } protected void showToast(String msg) { ToastUtils.show(msg); } protected abstract @LayoutRes int getLayoutId(); protected abstract void init(Bundle savedInstanceState); } 

同样我们项目的BaseFragment继承RxFragment(注意使用继承V4包下的RxFragment),如下:

public abstract class BaseFragment extends RxFragment { public View rootView; public LayoutInflater inflater; @Nullable @Override public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); this.inflater = inflater; if (rootView == null) { rootView = inflater.inflate(this.getLayoutId(), container, false); init(savedInstanceState); } ViewGroup parent = (ViewGroup) rootView.getParent(); if (parent != null) { parent.removeView(rootView); } return rootView; } protected abstract int getLayoutId(); protected abstract void init(Bundle savedInstanceState); protected void showToast(String msg) { ToastUtils.show(msg); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onDestroyView() { super.onDestroyView(); } } 

3.使用compose操作符管理Retrofit生命周期了:

myObservable .compose(bindToLifecycle()) .subscribe(); 或者 myObservable .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribe(); 

关于RxLifecycle的详细使用方法可以参考 RxLifecycle官网

七.如何使用封装

public interface IdeaApiService { / * 此接口服务器响应数据BasicResponse的泛型T应该是List<MeiZi> * 即BasicResponse<List<MeiZi>> * @return BasicResponse<List<MeiZi>> */ @Headers("Cache-Control: public, max-age=10")//设置缓存 缓存时间为100s @GET("福利/10/1") Observable<List<MeiZi>> getMezi(); / * 登录 接口为假接口 并不能返回数据 * @return */ @POST("login.do") Observable<LoginResponse> login(@Body LoginRequest request); / * 刷新token 接口为假接口 并不能返回数据 * @return */ @POST("refresh_token.do") Observable<RefreshTokenResponseBean> refreshToken(@Body RefreshTokenRequest request); @Multipart @POST("upload/uploadFile.do") Observable<BasicResponse> uploadFiles(@Part List<MultipartBody.Part> partList); } 

2.定义一个RetrofitHelper 类,通过IdeaApi来获取IdeaApiService的实例。

public class RetrofitHelper { private static IdeaApiService mIdeaApiService; public static IdeaApiService getApiService(){ return mIdeaApiService; } static { mIdeaApiService= IdeaApi.getApiService(IdeaApiService.class, Constants.API_SERVER_URL); } } 

3.在Activity或者Fragment中发起网络请求

 / * Get请求 * @param view */ public void getData(View view) { RetrofitHelper.getApiService() .getMezi() .compose(this.<List<MeiZi>>bindToLifecycle()) .compose(ProgressUtils.<List<MeiZi>>applyProgressBar(this)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new DefaultObserver<List<MeiZi>>() { @Override public void onSuccess(List<MeiZi> response) { showToast("请求成功,妹子个数为" + response.size()); } }); } 

八.小结

本篇文章主要讲解了Rxjava和Retrofit的二次封装。以上内容也是笔者参考多方面的资料经过长时间的改动优化而来。但鉴于本人能力有限,其中也避免不了出现不当之处。还请大家多多包涵。另外,在投稿郭神公众号时文章可能还存在很多处理不优雅的地方,比如对响应数据的处理以及对Loading的处理。在投稿被推送后收到了很多小伙伴的建议,因此笔者也参考了大家的意见并做了优化,在此感谢大家。最后如果有疑问欢迎在文章留言评论。

源码传送门

好库推荐

给大家推荐一下BannerViewPager。这是一个基于ViewPager实现的具有强大功能的无限轮播库。通过BannerViewPager可以实现腾讯视频、音乐、酷狗音乐、支付宝、天猫、淘宝、优酷视频、喜马拉雅、网易云音乐、哔哩哔哩等APP的Banner样式以及指示器样式。

欢迎大家到github关注BannerViewPager!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231802.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 强化学习 模仿学习 于robot[通俗易懂]

    强化学习 模仿学习 于robot[通俗易懂]写在前面:分享知识是再好不过的事情。这篇文章主要是总结自己最近看的一些文章以及相关知识。自己在暑假实习的时候学习的就是在物理仿真平台上做robot的强化学习,未来读PhD的时候也被老师继续分配到了这个方向,哈哈。可能要一直从入门到入土了,趁着最近写researchproposal的时候,将最近的理解记录一下。鉴于笔者知识水平有限,若有不妥当之处,还请指出。摘要:robot强化学习模仿学…

    2026年1月27日
    2
  • rpa是干什么的_rpa是什么技术

    rpa是干什么的_rpa是什么技术作者:影刀RPA链接:https://www.zhihu.com/question/382742683/answer/1367045898来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。RPA是什么?一句话让你明白这个技术是什么,一种模拟电脑鼠标键盘操作且可以代替人进行重复性、规则化电脑端操作的技术,展开想象会发现能够应用在公司各个部门各个业务线,简单整理如下:感觉还是很迷糊?钉钉跟客户发不同的消息内容(0编码4分钟完成)影刀RPA的..

    2025年10月18日
    4
  • Oracle删除表空间的同时删除数据文件[通俗易懂]

    临时表空间主要用途是在数据库进行排序运算[如创建索引、orderby及groupby、distinct、union/intersect/minus/、sort-merge及join、analyze命令]、管理索引[如创建索引、IMP进行数据导入]、访问视图等操作时提供临时的运算空间,当运算完成之后系统会自动清理。当临时表空间不足时,表现为运算速度异常的慢,并且临时表空间迅速增长到最大空

    2022年4月18日
    159
  • Keil 使用教程(详解)「建议收藏」

    Keil 使用教程(详解)「建议收藏」(1)打开Keil,点击project新建(2)选择合适的型号,没有STC的选项,不要紧,一般C51的好多兼容的(3)不用汇编的话,下面的这个对话框选择否就可以了(4)点击新建一个文件(5)选择保存,并命名为.c(6)双击SourceGroup(7)添加.c文件(8)写完程序后,点击标号1处的按钮,然后点击标号2处的output,依次点击3和4,生成.hex文件…

    2022年5月10日
    44
  • HDOJ 5000 Clone

    HDOJ 5000 Clone

    2022年1月4日
    41
  • 最近在学习mars老师的视频。按计划的。学习安卓

    转眼之间暑假就过去一大半了。还有14天就开学了。估计再过个一周,同学们就陆续回校了。这个假期借了很多书,虽然没有想象中那么高的效率,学习太多东西,不过还是学了点东西,起码自我感觉还算可以。我是先看了看java的基础知识,一本国外的java面向对象程序设计,说实话书挺好,不过对我不合适,学过c++之后,很多里面讲的思想差不多懂了,然后例子很多,看得有点头疼,应该找一本专门讲java语法的书的。那

    2022年3月8日
    70

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号