关闭

Retrofit结合RxJava的一次实践

标签: RetrofitRxJava框架
1040人阅读 评论(0) 收藏 举报
分类:

公司的一个项目中已经采用了Retrofit加RxJava的作为网络请求框架,强大的框架所以替换了那么久决定记录一下我的实践过程。

第一步,观察服务器返回的结果定义返回结构实体类

{
    "errno": 0,
    "errmsg": "操作成功",
    "data": []
}

所以我们可以定义个NetResponse< T >来作为一次服务器返回结果实体类其中的T是对应返回json中的data字段,可以是一个对象或者是一个列表结果,所以定义一个实体类出来。

public class NetResponse<T> {
    private String errno;
    private String errmsg;
    private T data;
}

第二步,初始化Retrofit
我们可以查看一下Square.Retrofit 官方对应的文档介绍,首先我们需要一个interface来存放接口请求地址,那么我们跟着文档的步骤来

public interface UserService {

    /**
     * 登录
     */
    @FormUrlEncoded
    @POST("/login/")
    Observable<NetResponse<UserInfo>> doLogin(@Field("account") String account, @Field("pwd") String password);
}

这里我们简单的举例为用户登录的过程,因为这是一个post请求所以按文档需求我们使用了FormUrlEncoded和Field注释字段。那如果是get请求呢?这里我也举个例子来表示get请求<这个例子是Retrofit的官方文档例子>

@GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);

这样我们就懂了 如何使用Retrofit来实现get/post请求操作了。定义完了请求interface后我们该下一步初始化Retrofit了,因为我项目中采用的是Fastjson作为json解析工具,这里需要先封装一个FastConverterFactory,为什么呢?因为Retrofit支持自定义Json解析类封装类似自带的Gson解析:

addConverterFactory(GsonConverterFactory.create())

所以我们也自己定义一个ConverterFactory来作为FastJson解析类。

final class FastResponseBodyConverter<T> implements Converter<ResponseBody, T> {

    private Type type;

    public FastResponseBodyConverter(Type type) {
        this.type = type;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        BufferedSource bufferedSource = Okio.buffer(value.source());
        String tempStr = bufferedSource.readUtf8();
        bufferedSource.close();
        LogUtil.w("FastResponseBodyConverter", "-- FastJsonRequestResponse = " + tempStr);
        return JSON.parseObject(tempStr, type);
    }
}

定义一个FastResponseBodyConverter来将json解析过程写在convert方法中

public class FastConverterFactory extends Converter.Factory {

    public static FastConverterFactory create() {
        return new FastConverterFactory();
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new FastResponseBodyConverter<>(type);
    }
}

再定义一个FastConverterFactory来初始化Fastjson解析,这样我们使用过程中不需要关心解析过程了,直接可以冲NetResponse中getT()方法得到我们想要的结果。
所以Retrofit的初始化过程我把定义了一个独有的类。

public class AppRetrofit extends BaseRetrofit {

    private AppService mService;
    private Retrofit mRetrofit;

    public AppService getService() {
        if (null == mService) {
            mService = getRetrofit().create(AppService.class);
        }
        return mService;
    }

    public Retrofit getRetrofit() {
        if (null == mRetrofit) {
            mRetrofit = new Retrofit.Builder()
                    .client(getOKHttpClient())
                    .baseUrl(BaseRetrofit.APP_URL)
                    .addConverterFactory(FastConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
        }
        return mRetrofit;
    }
}

需要注意的是一定要加入下面这句代码才能支持RxJava。

addCallAdapterFactory(RxJavaCallAdapterFactory.create())

其中的BaseRetrofit的完成类如下:

public class BaseRetrofit {

    private static final String TAG = "BaseRetrofit";

    /**
     * http请求成功
     */
    public static final String HTTP_SUCCESS = "0";

    public static final String USER_URL = "app_server_url";

    /**
     * 返回OkHttp配置
     */
    public OkHttpClient getOKHttpClient() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                LogUtil.e("Retrofit", message);
            }
        });
        HttpHeaderInterceptor headerInterceptor = new HttpHeaderInterceptor();
        return new okhttp3.OkHttpClient.Builder()
                .addNetworkInterceptor(interceptor)
                .addNetworkInterceptor(headerInterceptor)
                .build();
    }

    /**
     * 请求结果转换
     */
    public final Observable.Transformer mTransformer = new Observable.Transformer() {
        @Override
        public Object call(Object observable) {
            return ((Observable) observable)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .flatMap(new Func1() {
                        @Override
                        public Object call(Object response) {
                            return _flatResponse((NetResponse<Object>) response);
                        }
                    });
        }
    };

    /**
     * 将返回的数据结果直接转成想要的数据
     */
    public final <T> Observable<T> _flatResponse(final NetResponse<T> response) {
        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {
                if (!subscriber.isUnsubscribed()) {//  如果已经被回收的Subscribe的话就直接跳过
                    if (HTTP_SUCCESS.equals(response.getErrno())) {// 请求成功...
                        subscriber.onNext(response.getData());
                        subscriber.onCompleted();
                    } else {
                        LogUtil.e(TAG, "--- Retrofit request error ..........");
                        subscriber.onError(new ApiException(response.getErrno(), response.getErrmsg()));
                    }
                }
            }
        });
    }
}

其中我们还是需要解释一下Observable.Transformer对象的mTransformer,他的作用就是代码复用功效作用就是将我们返回的结果Observable< NetResponse< T > >转换成Observable跟操作符flatmap的效果类似,不同的是Transformer可以一开始就执行而不像flatmap需要等subscribe之后才调用,所以转换的话还是推荐使用Transformer类来解决,可以参考这篇文章避免打断链式结构:使用.compose( )操作符

第三步,调用。

public class UserNetRetrofit extends UserRetrofit {

    /**
     * 登录
     */
    public Observable<UserInfo> doLogin(String account, String password) {
        return getService().doLogin(account, password).compose(mTransformer);
    }
}

我们这里再一次把定义一个可见的类,把一切操作都写在这里面并且返回一个个Observable< T >给我们需要的View层自行拿取就好了。
所以代码的调用如下:

final UserNetRetrofit loginRetrofit = new UserNetRetrofit();
        Subscription subscription = loginRetrofit.doLogin(name, pwd)
                .subscribe(new Action1<UserInfo>() {
                    @Override
                    public void call(UserInfo info) {
                        // 拿到UserInfo对象自行操作
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable e) {
                        // 一次请求操作失败处理
                    }
                });
        BaseRetrofit.addSubscription(context, subscription);

如果你项目中采用的MVP模式可以把这段代码写到presenter层中,然后在call方法中分别回调成功或者失败到view层,代码看起来比较解耦不会很杂,ps:这里并没有那么处理。

最后,注意点:
是不是发现了addSubscription这是什么方法,Retrofit并没有提供这个东西。对,这是自己写的。

    /**
     * 存放Retrofit请求
     */
    public CompositeSubscription mCompositeSubscription;

    public void addSubscription(Subscription subscription) {
        if (null != mCompositeSubscription) {
            mCompositeSubscription.add(subscription);
        }
    }

就是这么个东西,定义一个CompositeSubscription对象用于存放每一次的请求,为了就是怕请求还没成功的时候界面finish后未能释放RxJava操作导致的内存泄露威胁。

    @Override
    protected void onDestroy() {
        //关闭界面上的请求
        if (null != mCompositeSubscription) {
            mCompositeSubscription.unsubscribe();
        }
        super.onDestroy();
    }

这样一次完整的请求封装就好了, 可以把一些公用的方法抽取放到BaseFragment或者BaseActivity中这样就不用写多余的代码。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:66307次
    • 积分:1443
    • 等级:
    • 排名:千里之外
    • 原创:65篇
    • 转载:4篇
    • 译文:1篇
    • 评论:11条
    最新评论