基于Retrofit扩展一个统一处理网络请求的CallBack


##思路 首先我们来思考几个场景: >- 场景一、 每次网络请求,都不能保证成功,如果你现在正在请求一段数据是为了加载一段网络列表,你在加载成功那里,把显示“正在加载”字样的View控件隐藏掉,那么如果请求失败,你是否还要再写一遍?? >- 场景二、 在APP请求网络过程中,难免遇到网络异常的情况,如果请求失败,就给用户一个比较友好的提示,比如 ‘网络开小差啦~’ 之类的提示。那么你是否每次请求都去写一遍 ‘网络开小差~’之类的提示语呢?? >- 场景三、 有时候用户的手机网络卡,当他打开一个页面发现数据很久都没有刷新出来,等的不耐烦就关闭了界面,当他关闭界面之后网络突然好了,这时候如果还按照你设定的流程走,会不会出现难以预料的问题呢? >- 场景四、 你现在在做一个有登录功能的APP,这时你的后台人员跑过来跟你说,后台返回来的数据中,某一个字段如果为一个特定的值,你就去自动打开某个页面(譬如:当isLogin=false的时候,要你去自动打开登录页面。当isBank=true的时候,需要自动打开银行卡页面。等等……)。那么你是会怎么去处理这些看似 “变态” 实际却很常用的需求呢?

以上场景是我们在APP开发中经常遇到的情况,那么我们接下来的代码,就是要解决这样的需求,我们要用最少的代码来完成最绕的需求。 ##代码篇 >- 1 : 由于篇章关系,这里不会贴出全部代码,但是会贴出主要关键代码,完整代码将在文章结尾贴出。 >- 2 : 本篇章适用于已经熟悉了**Retrofit的基本使用的人,所以如果对Retrofit都不会的话,建议先去熟悉一下Retrofit的基本使用。 ###解决场景一的需求: 我们当然不会每个成功或者失败的回调都去写一遍对“加载中”字样的控件的操作,这里封装了一个onFinally()方法,不管是网络请求成功,还是网络请求失败,都会去调用一次onFinally** 所以,我们可以把对控件的统一操作事件写在**onFinally**里面(譬如:将下拉刷新控件的加载中的状态,修改为加载完成的状态)

Net net = retrofitBase.getRetrofit().create(Net.class); Call<DataBean> call = net.getIndex(city); call.enqueue(new SCallBack<DataBean>(this) {     @Override     public void onSuccess(@NonNull DataBean result) throws Exception     {         Log.d("MainActivity", "onSuccess:"+result.getLat());     }          @Override     public void onCache(@NonNull DataBean result) throws Exception     {         Log.d("MainActivity", "onCache");     }          @Override     public void onFail(Throwable t)     {         super.onFail(t);         Log.d("MainActivity", "onFail:");     }          @Override     public void onFinally()     {         Log.d("MainActivity", "onFinally");     } }); 
  • 1 : 使用SICallBack,或者SCallBack 来替换Retrofit的CallBack,SCallBack 实现于SICallBack。
  • 2 : 传入上下文,支持传入的类型是:Context Fragment v4.app.Fragment
  • 3 : 重写**onFinally()**方法 。

###解决场景二的需求: 对于这种统一的网络出错提示,这里提供了一个统一处理方式。

import android.content.Context; import android.widget.Toast;  import com.xiaolei.exretrofitcallback.network.common.IFailEvent; import com.xiaolei.exretrofitcallback.network.common.SICallBack; /**  * Created by xiaolei on 2017/12/15.  */ public class MyFailEvent implements IFailEvent {     @Override     public void onFail(SICallBack callBack, Throwable t, Context context)     {         Toast.makeText(context, "哇哦~,您的网络有问题哦~", Toast.LENGTH_SHORT).show();     } } 
  • 1 : 新建一个类,实现IFailEvent接口。
  • 2 : 重写onFail方法。
  • 3 : 把类设置到Config里面去:Config.setFailedEventClass(MyFailEvent.class);

有人可能会说,你都定义封装好了,那如果我这个接口比较特殊,不想用这种统一的处理方式呢?? 这种情况的确存在,所以,如果您在某个接口不想使用统一的错误处理方式。那么在调用SICallBack的时候,重写 onFail(Throwable t)方法,并且不调用 super.onFail(Throwable t),那么就不会走统一处理的方式。

###解决场景三的需求: 这里就是一个网络请求慢,但是界面已经关闭的处理需求。 在**SICallBack**里面默认对Activity进行了判断,如果界面已经关闭,那么就算成功之后,还去更新界面UI已经失去意义,所以不会去执行onSuccess ,onFail,onFinally,方法。

@Override public void onFailure(Call<T> call, Throwable t) {     if (checkActivityFinish())         return;     try     {         onFail(t);     } finally     {         onFinally();     } } 
  • SICallBack里面,默认已经对本需求进行了处理。

###解决场景四的需求: 这个需求在很多APP里面都需要这种功能,有的人称之为路由之间的跳转。这里给一个例子:

import android.content.Context; import android.support.annotation.Nullable; import android.util.Log;  import com.xiaolei.exretrofitcallback.network.regist.OnCallBack; import com.xiaolei.exretrofitcallback.network.regist.ResponseBeanRegister; import com.xiaolei.exretrofitcallbackexample.Net.DataBean;  /**  * 这里是对地址进行拦截  * 如果是兰州市的地址,运行兰州市的方法,且不再执行onSuccess方法。  * 如果是深圳市的地址,运行深圳市的方法,不拦截,继续执行onSuccess方法。  * Created by xiaolei on 2017/12/15.  */  public class MyRegister extends ResponseBeanRegister<DataBean> {     @Nullable     @Override     public String filter(DataBean bean)     {         return bean.getLat();     }          @OnCallBack(value = "36.06108")//兰州市     public void onInLanzhou(Context context)     {         Log.d("MainActivity", "拦截:兰州市");     }      @OnCallBack(value = "22.54309",stopNextStep = false)//深圳市     public void onInShenzhen(Context context)     {         Log.d("MainActivity", "拦截:深圳市");     }      } 
  • 1、 :新建一个类,继承**ResponseBeanRegister&lt;T&gt;**,泛型里,则写上你的本地请求返回数据的类型,比如:一个Bean,或者,String 字符串。
  • 2、 :你的每次网络请求成功后都会自动调用这个onfilter方法,所以需要重写**String filter(T bean);**方法。返回的数据则是你需要去判断的数据。比如:你的泛型是DataBean,你需要判断DataBean里面 lat字段的值,那么你就应该这么写:
@Nullable @Override public String filter(DataBean bean) {     return bean.getLat(); } 
  • 3、 : 定义一个方法,使用用**@OnCallBack**去注解,示例如下:
@OnCallBack(value = "22.54309",stopNextStep = false)//深圳市 public void onInShenzhen(Context context) {     Log.d("MainActivity", "拦截:深圳市"); } 

这里有2个需要注意的: ①:OnCallBack里面,有两个参数,第一个参数value是用来比较的值,当onfilter方法返回的值等于value的时候,则会自动调用当前方法,第二个参数stopNextStep是一个布尔值,不写默认为true。当为true的时候,则当调用完本方法,不再调用onSuccess方法。当为false,则会继续调用onSuccess方法。 >stopNextStep = false -> 本方法 -> onSuccess -> onFinally >stopNextStep = true -> 本方法 -> onFinally

②:对于定义的方法的参数,支持两个,一个是CallBack的返回的参数,一个则是Context上下文。 支持自动注入值的参数类型

  • 4、 :在Config里注册:Config.registResponseBean(DataBean.class,MyRegister.class);//路由之间跳转的注册 。可注册多个Bean以及对应的ResponseRegister.

#结尾 移步这里获取Demo以及完整关键源码: Gtihub:https://github.com/xiaolei123/ExRetrofitCallback

gradle直接使用:

compile 'com.xiaolei:ExRetrofitCallBack:1.0.1' 

本文发表于2017年12月18日 10:38
(c)注:本文转载自https://my.oschina.net/xiaolei123/blog/1591244,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 962 讨论 8 喜欢 0

讨论

Перезвоните пожалуйста по телефону 8 (499) 322-46-85 , Валерий.

人觉得很赞      回复


老哥 你给我电话我也打不过去啊 -_-!!!

人觉得很赞      回复


周娱

君子和而不同
按照自己的方式,去度过人生

6174 1959597
抢先体验

扫码体验
趣味小程序
文字表情生成器

加入组织

扫码添加周娱微信
备注“加入组织”
邀请进开发群

闪念胶囊

天空不是人类休息的地方,人类应该去亲近海洋。

一个人的正直程度,取决于他肯为原则付出的牺牲。

每个人都有一个最有创造力的年龄窗口,它大概只有十来年的样子,哪怕你是那种拥有元力的人。你能取得多大成就,取决于你在这个时间窗口,离你最近的是什么行业,它直接决定了你的人生轨迹。这个行业上升还是衰落,甚至你在这个行业中处于什么生态位,都和你的奋斗无关。

人的脑子就像在半山腰,不进则退,没有任何约束就滚下去了,因此需要自律。

大多数人程序员都高估了他们一天能完成的开发量,但低估了他们一年能学习到的东西。 ​​​

“决定我们成为什么样的人,不是我们的能力,而是我们的选择。”

让一个团队走向平庸的最佳方式,是让成员们持续地干那些不让他们感到自豪的事情。

最近1 2年发现成长的最好方式是研究开源的项目,自己实践。成长速度非常的快,一个好的项目需要考虑的细节很多。

不积跬步无以至千里,越焦虑越要扎实干。

Copyright © 2016 - 2018 Cion.
All Rights Reserved.
备案:鲁ICP备16007319号.