最近最火的网络库应该是Retrofit了,我也在项目中耍了起来,可以说是非常的有趣。 个人感觉是Retrofit网络库是简洁,实用和逻辑清晰,将网络接口和回调逻辑分层处理,在逻辑层你都可以不用知道网络接口的类型和参数。

我就开始从自己的应用场景说起吧。

Retrofit 2.0 接入

首先,我们应该是添加依赖,这应该大家都很熟悉吧,我就添加了我项目中需要用的依赖。

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

添加了这三个依赖我们就可以正常的耍起来了,当然如果你要用rxJava别忘了添加相关依赖,这里我就不说了。

1.先把RetrofitClient搞起来

我们要先知道Retrofit其实一个对okhttp的一个封装,它是基于okhttp的,所以okhttp的有些特性也可以使用。不多说,我们先把Retrofit封装起来使用。

首先,我们需要定义一个网络请求的接口,它是负责写所有网络请求的,需要根据Retrofit的规范来写,待会下面会详细说。

//Retrofit 网络请求接口
public interface RetrofitNetApi 

然后,我们还需要OkHttpClient,通过它可以设置一些属性,例如失败重连和网络拦截器,网络拦截可以设置header


private static final OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
            .retryOnConnectionFailure(true)
            .addNetworkInterceptor(new StethoInterceptor())
            .addInterceptor(chain -> {
                //添加header
                Request original = chain.request();
                Request request = original.newBuilder()
                        .header("X-Token", token)
                        .addHeader("X-Device-ID", deviceID)
                        .addHeader("X-UID", userID + "")
                        .addHeader("X-App-Version", version + "")
                        .addHeader("user-agent", UA)
                        .build();

                return chain.proceed(request);
            })
            .build();

这种设置header的方式是okhttp的方式,通过拦截器设置header;其实,Retrofit也有设置header的方式,但是它是属于传参数的形式,需要每一个网络接口请求的时候进行设置,不利于封装,重用了代码。例如:

@GET("user")
Call<ResponseBody> getUser(@Header("header1") String header)

最后,封装一个通用的RetrofitClient用于调用网络请求接口。

    public static RetrofitNetApi getNetApi() {
        if (RetrofitApi == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .client(mOkHttpClient)
                    .baseUrl(getUrl())
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            RetrofitApi = retrofit.create(RetrofitNetApi.class);
        }
        return RetrofitApi;
    }

baseUrl()是你的基础网络请求接口,例如是”www.shadow.com/user”,那个”baseUrl”就是”www.shadow.com”。addConverterFactory(GsonConverterFactory.create())是吧json结果并解析成DAO,也可以添加其他的解析方式,但是必须换其他方式的依赖。

2.定义Retrofit网络接口

首先是一个简单的Get请求 网络接口是这样的”www.shadow.com/xxx/session“ 那我们可以这样

@GET("account/session")
Call<ResponseBody> getSession();

还有很多

例如Get请求 “www.shadow.com/xxxx/book?pageIndex=1&pageSize=20”

你可以这么拼接你的网络请求,使用操作符@Query

@GET("xxxx/book")
Call<ResponseBody> book(@Query("pageIndex") String pageIndex, @Query("pageSize") String pageSize);

还有Get请求 “www.shadow.com/xxxx/bookname” 通过替换bookname来请求接口, 可以使用操作符@Path

@GET("xxxx/{bookname}")
Call<ResponseBody> bookname(@Path("bookname") String bookname);

Post请求 “www.shadow.com/xxxx/booklist” 需要提交参数,可以使用操作符@Field,而且不用忘记加上@FormUrlEncoded.

@FormUrlEncoded
@POST("xxxx/booklist")
Call<ResponseBody> booklist(@Field("booklist") String booklist);

而且@Field不限制请求方式,你用Put也可以,但是不能忘记@FormUrlEncoded

@FormUrlEncoded
@PUT("xxxx/booklist")
Call<ResponseBody> booklist(@Field("booklist") String booklist);

其实Retrofit的请求方式很灵活,几乎能满足你想要的各种姿势。

例如是这样的Get请求 “www.shadow.com/xxxx/bookname/book?pageIndex=1&pageSize=20”

@GET("xxxx/{bookname}/book")
Call<ResponseBody> bankLimit(@Path("bookname") String bookname, @Query("pageIndex") String pageIndex,@Query("pageSize") String pageSize);

或者是这样的Post请求 “www.shadow.com/xxxx/bookname/booklist”


@FormUrlEncoded
@POST("xxxx/{bookname}/booklist")
Call<ResponseBody> bonusAutoInvest(@Path("bookname") int bookname, @Field("booklist") boolean booklist);

就是这么的好玩

封装通用网络库

按照以上说的,我们已经把网络接口定义好了,那现在需要封装通用网络库。 上面的代码,可以发现我的网络接口返回的都是Call<ResponseBody>,而不是Observable<T>

Call<T>Retrofit的一个Callback形式的参数回调,T是任意泛型,这个Call<T>有一个网络发送请求的方法,是同步的。

ResponseBodyokhttp的一个请求体,可以封装json

这样使用,是因为我不想直接获取已经解析好的bean,而是拿到json,更加的灵活判断网络请求的各种状况。

以下代码是用RxJava封装的网络库


private Observable<String> getResults(Call<ResponseBody> call, int delay) {

        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(final Subscriber<? super String> subscriber) {
                try {
                    retrofit2.Response<ResponseBody> response = call.execute();
                    String result = response.body() != null ? response.body().string() : "";
                    String error = response.errorBody() != null ? response.errorBody().string() : "";
                    int code = response.code();
                   
                    if (response.isSuccessful()) {  //返回值在200至300之间表示返回成功
                        //根据某种约定的特殊处理 没有返回值
                        if (!result.startsWith("{") && (!result.startsWith("[")) || code == 204 || result.equals("{}"){ 
                            subscriber.onNext("ok");
                        } else {    //有返回值
                            subscriber.onNext(result);
                        }

                    } else {    //请求失败时的处理
                        if (TextUtils.isEmpty(error)) {    //没有返回标准的报错信息
                            subscriber.onError(new Exception("code:" + code));
                        } else {
                            subscriber.onError(new Exception(error));
                        }
                    }
                } catch (Exception e) {
                            subscriber.onError(e);
                }
            }

        }).delay(delay, TimeUnit.MILLISECONDS);
    }


如代码,我可以把网络接口Call<ResponseBody>传参进去,执行网络请求,然后根据返回的json,不同的情况做不同的处理,最后用subscriber回调正确或者错误的结果。正确的json可以解析成我们需要的bean,错误的json可以根据不同的状况作出不同的错误处理,这样一来比较灵活和解耦,能处理各种不同的网络请求的需求。

最外层的就是普通的Rxjava调用了,这里就不描述了。

最后,这就是我使用的Retrofit 2.0网络库的封装和各种应用场景,给我的感觉就是Retrofit非常的简洁和高效。

最后

这是一个简洁实用的网络封装,记录一下思路。