Android 我的Retrofit+Rxjava封装,不搞花里胡俏

前言

从我最开始用rx和retrofit.到现在,快3年了.

这个库的内容,算是沉淀下来的东西.

个人用这个做过的项目也有很多个了.和项目中用的有点区别.

因为不能随便重构的原因,比项目里的更好.哈哈.

目录:

image

初始化:

NetWorkManager.init(String baseUrl, Application context)

难点1 BaseBean:

作为一个库,这个类是一个头疼的问题.因为强耦合.

我们一般写的baseBaen都是这样的:

class BaseBean<T>{
  String code;
  T data;
  String msg;
}

不同的人,有不同的协议,字段名会不一样,如果用这样的,明显是不行的.

这个库是这样的(ParseInfo):

你只需要定义自己的basebean规则,即可

image

例子

 NetWorkManager.addParseInfo(
                new RxParseInfo("code", "data", "msg", "200") //200代表成功时的code.
        );

这里传入的参数都是key的名字.

目前支持3个key值.我觉得基本够用了.

codeKey判断成功

dataKey返回数据

msgKey服务器返回消息

库是如何判断接口请求成功的

ParseInfo 里默认通过判断successCode与返回的codeKey的值进行比较的

 public boolean isSuccess(JsonObject asJsonObject) {
        if (checkSuccess != null) {
            return checkSuccess.isSuccess(asJsonObject);
        }
        String code = asJsonObject.get(codeKey).toString();
        return TextUtils.equals(code, successCode);
    }

也可以自定义判断是否请求成功

ParseInfo使用setCheckSuccess().非必须.主要是为了扩展.

new ParseInfo("code", "data", "msg", "200")
 .setCheckSuccess(new ParseInfo.CheckSuccess() {
                    @Override
                    public boolean isSuccess(JsonObject asJsonObject) {
                        return false;
                    }
                })

请求:

public interface JApi {

    /**
     * 上传文件
      */
    @POST
    @Multipart
    Observable<String> post(@Url String url, @PartMap HashMap<String, RequestBody> params);

    /**
     * 通用POST
     *
     */
    @POST
    Observable<String> post(@Url String url, @Body String json);

    /**
     * 通用POST
     */
    @POST
    Observable<String> post(@Url String url, @Body SimpleParams json);

    /**
     * 通用get
     */
    @GET
    Observable<String> get(@Url String url, @QueryMap SimpleParams params);

}

这里写了4个通用的retrofit的请求.我个人觉得是可以满足大部分的需求了.

如果满足不了.就写点定制的就好了.有人会觉得这么写不行,实际上,我就用这个已经写了很多项目了.

有人会问,为什么这里都是Observable<String>,往后面看就知道了.嘿嘿

RetrofitUtil

这里使用了饿汉式懒加载单例.

public class RetrofitUtil {
    /**
     * 服务器地址
     */
    private static String API_HOST;
    private static Application mContext;
    private static final HashMap<Class, Object> apis = new HashMap<>();

    @SuppressWarnings("unchecked")
    public static <T> T getApi(Class<T> c) {
        Object o = apis.get(c);
        if (null == o) {
            o = getInstance().create(c);
            apis.put(c, o);
        }
        return (T) o;
    }

    public static synchronized void init(String baseUrl, Application context) {
        if (TextUtils.isEmpty(baseUrl)) {
            return;
        }
        mContext = context;
        API_HOST = baseUrl;
        Instance.retrofit = Instance.getRetrofit();
        apis.clear();
    }

    public static Retrofit getInstance() {
        return Instance.retrofit;
    }

    private static class Instance {
        private static Retrofit retrofit = getRetrofit();

        private static Retrofit getRetrofit() {
            OkHttpClient.Builder client = new OkHttpClient.Builder()
                    //拦截并设置缓存
                    .addNetworkInterceptor(new CacheInterceptor())
                    //拦截并设置缓存
                    .addInterceptor(new CacheInterceptor())
                    .cache(new Cache(mContext.getCacheDir(), 10240 * 1024));
            // 设置代理
            if (NetWorkManager.getProxy() != null) {
                client.proxy(NetWorkManager.getProxy());
            }

            for (Interceptor i : NetWorkManager.mInterceptors) {
                client.addInterceptor(i);
            }
            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                client.addInterceptor(interceptor);
            }
            return new Retrofit.Builder()
                    .client(client.build())
                    .baseUrl(API_HOST)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
    }

可以设置缓存,添加代理,重置baseurl

对Retrofit.create创建的实体类,进行了缓存.

看了半天,先来个例子吧:

Disposable login = RetrofitUtil.getApi(JApi.class)
                .get("/login", SimpleParams.create()
                        .putP("key1", 1)
                        .putP("key2", 2)
                        .putP("key3", 2)
                        .putP("key4", 3)
                )
                .compose(JRxCompose.normal())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {

                    }
                });

一个简单的请求就是这样的.

有人看了会问, JRxCompose是啥?

JRxCompose

先来张目录图

image

再来张代码

image

这里为什么要写JsonArrayParesTransformerJsonParesTransformer.

因为在组件化的时候,跨组件GSON解析时,泛型是会丢失的.我不知道现在解决没.

所以使用这两个来统一解析结果.

如果你细心就会发现.JApi的方法,的返回参数都是Observable<String>

也就是统一先用String接收结果,然后再解析成最终结果.


看到这里,你满足了吗? 我是不满足的.哈哈

难点2 取消网络请求

如何舒服的取消请求回调一直是个头疼的问题

不取消就会内存泄露,调用已关闭的activity,造成崩溃.

当然,现在有RxLifecyle之类的库,很方便.

这里我简单实现了一个.不过有版本限制.依赖Android自带的Lifecycle

JApiImpl

public class JApiImpl implements JApi, LifecycleObserver, ObservableTransformer<String, String> {

    public static JApi getApi() {
        return RetrofitUtil.getApi(JApi.class);
    }

    public static JApiImpl with(Lifecycle lifecycle) {
        JApiImpl JApiImpl = new JApiImpl();
        lifecycle.addObserver(JApiImpl);
        return JApiImpl;
    }

    public static JApiImpl with(Fragment fragment) {
        return with(fragment.getLifecycle());
    }

    public static JApiImpl with(AppCompatActivity activity) {
        return with(activity.getLifecycle());
    }

    private Disposable disposable;

    @Override
    public ObservableSource<String> apply(Observable<String> upstream) {
        return upstream.doOnSubscribe(disposable -> this.disposable = disposable);
    }

    private void cancel() {
        if (this.disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        this.cancel();
        Log.i("233", "取消了请求");
    }

    @Override
    public Observable<String> post(String url, HashMap<String, RequestBody> params) {
        return getApi().post(url, params).compose(this);
    }

    @Override
    public Observable<String> post(String url, String json) {
        return getApi().post(url, json).compose(this);
    }

    @Override
    public Observable<String> post(String url, SimpleParams params) {
        return getApi().post(url, params).compose(this);
    }

    @Override
    public Observable<String> get(String url, SimpleParams params) {
        return getApi().post(url, params).compose(this);
    }

}

实现了JApi,LifecycleObserver,ObservableTransformer

LifecycleObserver是为了利用现在android自带的Lifecycle实现取消回调

ObservableTransformer是为了转换Observer.拿到Disposable.

这么改一下后.请求就可以这样:

            JApiImpl.with(this)
                .get("/login", SimpleParams.create()
                        .putP("key1", 1)
                        .putP("key2", 2)
                        .putP("key3", 2)
                        .putP("key4", 3)
                )
                .compose(JRxCompose.normal())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {

                    }
                });

添加加密/解密

        NetWorkManager.initKey("私钥", "公钥");//加密解密

设置超时时间

        NetWorkManager.setDefaultTimeOut(20);//秒

设置重试次数

        NetWorkManager.setDefaultRetry(5);//重试次数

设置全局异常统一回调

   NetWorkManager.setExceptionListener(new onExceptionListener() {
            @Override
            public String onError(Throwable throwable) {
                return null; 
            }
        });

设置添加全局code状态处理

  NetWorkManager.setApiCallBack(new APICallBack() {
            @Override
            public String callback(String code, String resultData) {
                JsonElement jsonElement = JSONFactory.parseJson(resultData);
                return JSONFactory.getValue(jsonElement, "message");
            }
        });

设置打开服务器返回msg异常

如果callback不处理,并打开isOpenApiException,则抛出服务器返回msg信息

NetWorkManager.setOpenApiException(true);

异常的处理逻辑

    String errorMsg = null;
    //通过code获取注册的接口回调.
    APICallBack apiCallback = NetWorkManager.getApiCallback();
    if (apiCallback != null) {
        String callbackMsg = apiCallback.callback(code, response);
        if (!TextUtils.isEmpty(callbackMsg)) {
            errorMsg = callbackMsg;
        }
    }

    //如果callback不处理,并打开isOpenApiException,则抛出服务器返回msg信息
    if (TextUtils.isEmpty(errorMsg) && NetWorkManager.isOpenApiException()) {
        errorMsg = msg;
    }
    //抛出异常,走到onError.
    throw new APIException(code, errorMsg);

解析结果是Object或Array的例子:

        //结果是一个Object
        JApiImpl.with(this)
                .post("/Login", SimpleParams.create())
                .compose(JRxCompose.obj(Login.class))
                .subscribe(new Consumer<Login>() {
                    @Override
                    public void accept(Login login) throws Exception {

                    }
                });
        //结果是集合
        JApiImpl.with(this)
                .post("/Login", SimpleParams.create())
                .compose(JRxCompose.array(Login.class))
                .subscribe(new Consumer<List<Login>>() {
                    @Override
                    public void accept(List<Login> logins) throws Exception {
                        
                    }
                });

简单的Observer

这里支持传入CompositeDisposable,添加当前的Disposable,用于取消回调,如果你用了上面的
JApiImpl,那么这里可以不传CompositeDisposable,这个是我最早实现统一取消回调的逻辑.

/**
 * @author jlanglang  2016/11/14 17:32
 * @版本 2.0
 * @Change
 */
public abstract class SimpleObserver<T> implements Observer<T> {
    protected Disposable mDisposable;
    private CompositeDisposable mCompositeDisposable;

    public SimpleObserver() {
        this(null);
    }

    public SimpleObserver(CompositeDisposable compositeDisposable) {
        mCompositeDisposable = compositeDisposable;
    }

    @Override
    public void onSubscribe(@NonNull Disposable d) {
        mDisposable = d;
        try {
            mCompositeDisposable.add(d);
        } catch (Exception ignored) {

        }
    }

    @Override
    public void onNext(T t) {
        call(t);
    }

    @Override
    public void onError(Throwable e) {
     
    }


    @Override
    public void onComplete() {

    }

    public abstract void call(@NonNull T t);
}

ToastObserver

在实际使用的时候,我们一般不会每个请求都弹Toast.
所以.如果需要默认弹Toast的请求.可以使用这个类.

/**
 * @author jlanglang  2016/11/14 17:32
 */
public abstract class ToastObserver<T> extends SimpleObserver<T> {

    public ToastObserver() {
        this(null);
    }

    public ToastObserver(CompositeDisposable com) {
        super(com);
    }

    @Override
    public void onError(Throwable e) {
        String errorMsg = NetWorkErrorFactory.disposeError(e);
        if (!TextUtils.isEmpty(errorMsg)) {
            Toast.makeText(NetWorkManager.getContext(), errorMsg, Toast.LENGTH_SHORT).show();
        }
    }
}

异常解析工厂

这个类,其实让我很纠结,因为这个类好像没什么作用.又好像又作用.
但是太绕了.
比如在NetWorkTransformer中抛出的APIException,以及初始化设置的onExceptionListener
都是这里来处理的.
但不调用这个方法.这个方法就无意义.

我是在上面的ToastObserver中调用了这个方法.
你可以自定义这个方法在哪调用.

 /**
     * 异常时处理工厂
     *
     * @param throwable 异常
     * @return 获取异常提示消息
     */
    public static String disposeError(Throwable throwable) {
        Class<? extends Throwable> throwableClass = throwable.getClass();
        //处理Api自定义异常处理,请求是成功的,如果需要特殊处理,使用APICallBack
        if (throwableClass.equals(APIException.class)) {
            return throwable.getMessage();
        }
        //处理error异常,http异常
        onExceptionListener exceptionListener = NetWorkManager.getExceptionListener();
        if (exceptionListener != null) {
            return exceptionListener.onError(throwable);
        }
        return "";
    }

结语

大致使用就这些了.

库里还包含了rxbus.

欢迎大家点赞,留言提建议

github地址: JRxRetrofit

交流群:

Flutter:782978118

Android:493180098

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • OkGo,一个专注于让网络请求更简单的框架,与RxJava完美结合,比Retrofit更简单易用。 OkGo - ...
    压抑的内心阅读 16,436评论 0 9
  • 文章转自:http://gank.io/post/560e15be2dca930e00da1083作者:扔物线在正...
    xpengb阅读 7,017评论 9 73
  • 暑假中,我没有参加校外的补习、兴趣大军,也没有去任何地方旅游,基本上天天在家,过着有规律又宁静闲适的生活。...
    八二年的葡萄干阅读 555评论 0 1
  • 2018.03.27今晚崇远饭前就写完作业了,(游泳馆维修不用去游泳了,我也非常高兴)饭后崇远说骑自行车,我说“好...
    幸福树328阅读 86评论 0 0