您当前的位置: 首页 >  网络

Kevin-Dev

暂无认证

  • 0浏览

    0关注

    544博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Android -- 网络请求】Retrofit + RxJava + OkHttp 网络请求

Kevin-Dev 发布时间:2022-03-19 11:13:45 ,浏览量:0

简介
  • Retrofit 是 Square 公司开发的一款正对 Android 网络请求的框架。底层基于 OkHttp 实现,OkHttp 已经得到了 google 官方的认可。

  • OkHttp 也是 Square 开源的网络请求库

  • RxJava 在 GitHub 主页上的自我介绍是 " a library for composing asynchronous and event-based programs using observable sequences for the Java VM "(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。总之就是让异步操作变得非常简单。

职责:Retrofit 负责请求的数据和请求的结果,使用接口的方式呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。

RxJava + Retrofit + okHttp 已成为当前 Android 网络请求最流行的方式。

结构图

网络请求

1. 在 app/build.gradle 中添加依赖

	implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.google.code.gson:gson:2.8.9'
    implementation 'io.reactivex:rxjava:1.2.1'
    implementation 'io.reactivex:rxandroid:1.2.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

2. 创建一个统一生成接口实例的管理类

/**
 * Created on 2022/3/18 10:33
 *
 * @author Gong Youqiang
 */
public class RetrofitServiceManager {
    private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
    private static final int DEFAULT_READ_TIME_OUT = 10;
    private Retrofit mRetrofit;
    private RetrofitServiceManager(){
        // 创建 OKHttpClient
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
        builder.writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//写操作 超时时间
        builder.readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//读操作超时时间

        // 添加公共参数拦截器
        HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
                .addHeaderParams("paltform","android")
                .addHeaderParams("userToken","1234343434dfdfd3434")
                .addHeaderParams("userId","123445")
                .build();
        builder.addInterceptor(commonInterceptor);


        // 创建Retrofit
        mRetrofit = new Retrofit.Builder()
                .client(builder.build())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(Constants.BASE_URL)
                .build();
    }

    private static class SingletonHolder{
        private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager();
    }

    /**
     * 获取RetrofitServiceManager
     * @return
     */
    public static RetrofitServiceManager getInstance(){
        return SingletonHolder.INSTANCE;
    }

    /**
     * 获取对应的Service
     * @param service Service 的 class
     * @param 
     * @return
     */
    public  T create(Class service){
        return mRetrofit.create(service);
    }
}

说明:创建了一个RetrofitServiceManager类,该类采用单例模式,在私有的构造方法中,生成了Retrofit 实例,并配置了OkHttpClient和一些公共配置。提供了一个create()方法,生成接口实例,接收Class范型,因此项目中所有的接口实例Service都可以用这个来生成,代码如下:

mGankService = RetrofitServiceManager.getInstance().create(GankService.class);

3. 网络请求结果基类

/**
 * Created on 2022/3/18 10:26
 * 网络请求结果基类
 * @author Gong Youqiang
 */
public class BaseResponse {
    public int status;
    public String message;

    public T data;

    public boolean isSuccess(){
        return status == 200;
    }
}

4. 创建一个业务 ObjectLoader

/**
 * Created on 2022/3/18 10:31
 * 将一些重复的操作提出来,放到父类以免Loader 里每个接口都有重复代码
 * @author Gong Youqiang
 */
public class ObjectLoader {
    /**
     *
     * @param observable
     * @param 
     * @return
     */
    protected   Observable observe(Observable observable){
        return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}

5. 拦截器

/**
 * Created on 2022/3/18 10:30
 * 拦截器
 * @author Gong Youqiang
 */
public class HttpCommonInterceptor implements Interceptor {
    private Map mHeaderParamsMap = new HashMap();
    public HttpCommonInterceptor() {

    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Log.d("HttpCommonInterceptor","add common params");
        Request oldRequest = chain.request();

        // 新的请求

        Request.Builder requestBuilder =  oldRequest.newBuilder();
        requestBuilder.method(oldRequest.method(), oldRequest.body());
        //添加公共参数,添加到header中
        if(mHeaderParamsMap.size() > 0){
            for(Map.Entry params:mHeaderParamsMap.entrySet()){
                requestBuilder.header(params.getKey(),params.getValue());
            }
        }

        Request newRequest = requestBuilder.build();

        return chain.proceed(newRequest);
    }

    public static class Builder{
        HttpCommonInterceptor mHttpCommonInterceptor;

        public Builder(){
            mHttpCommonInterceptor = new HttpCommonInterceptor();
        }

        public Builder addHeaderParams(String key, String value){
            mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
            return this;
        }

        public Builder  addHeaderParams(String key, int value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, float value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, long value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, double value){
            return addHeaderParams(key, String.valueOf(value));
        }


        public HttpCommonInterceptor build(){
            return mHttpCommonInterceptor;
        }
    }
}

6. PayLoad.java

/**
 * Created on 2022/3/18 10:32
 *
 * @author Gong Youqiang
 */
public class PayLoad implements Func1 {
    @Override
    public T call(BaseResponse tBaseResponse) {//获取数据失败时,包装一个Fault 抛给上层处理错误
        if(!tBaseResponse.isSuccess()){
            throw new Fault(tBaseResponse.status,tBaseResponse.message);
        }
        return tBaseResponse.data;
    }
}

7. 异常处理类

/**
 * Created on 2022/3/18 10:29
 * 异常处理类,将异常包装成一个 Fault ,抛给上层统一处理
 * @author Gong Youqiang
 */
public class Fault extends RuntimeException {
    private int errorCode;

    public Fault(int errorCode,String message){
        super(message);
        errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }
}

8. BasicParamsInterceptor.java

/**
 * Created on 2022/3/18 10:27
 *
 * @author Gong Youqiang
 */
public class BasicParamsInterceptor implements Interceptor {
    Map queryParamsMap = new HashMap();
    Map paramsMap = new HashMap();
    Map headerParamsMap = new HashMap();
    List headerLinesList = new ArrayList();

    private BasicParamsInterceptor() {

    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        Request.Builder requestBuilder = request.newBuilder();

        // process header params inject
        Headers.Builder headerBuilder = request.headers().newBuilder();
        if (headerParamsMap.size() > 0) {
            Iterator iterator = headerParamsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
            }
        }

        if (headerLinesList.size() > 0) {
            for (String line: headerLinesList) {
                headerBuilder.add(line);
            }
            requestBuilder.headers(headerBuilder.build());
        }
        // process header params end


        // process queryParams inject whatever it's GET or POST
        if (queryParamsMap.size() > 0) {
            request = injectParamsIntoUrl(request.url().newBuilder(), requestBuilder, queryParamsMap);
        }

        // process post body inject
        if (paramsMap.size() > 0) {
            if (canInjectIntoBody(request)) {
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                for(Map.Entry entry : paramsMap.entrySet()) {
                    formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
                }

                RequestBody formBody = formBodyBuilder.build();
                String postBodyString = bodyToString(request.body());
                postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  bodyToString(formBody);
                requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
            }
        }

        request = requestBuilder.build();
        return chain.proceed(request);
    }
    private boolean canInjectIntoBody(Request request) {
        if (request == null) {
            return false;
        }
        if (!TextUtils.equals(request.method(), "POST")) {
            return false;
        }
        RequestBody body = request.body();
        if (body == null) {
            return false;
        }
        MediaType mediaType = body.contentType();
        if (mediaType == null) {
            return false;
        }
        if (!TextUtils.equals(mediaType.subtype(), "x-www-form-urlencoded")) {
            return false;
        }
        return true;
    }

    // func to inject params into url
    private Request injectParamsIntoUrl(HttpUrl.Builder httpUrlBuilder, Request.Builder requestBuilder, Map paramsMap) {
        if (paramsMap.size() > 0) {
            Iterator iterator = paramsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue());
            }
            requestBuilder.url(httpUrlBuilder.build());
            return requestBuilder.build();
        }

        return null;
    }

    private static String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if(copy != null)
                copy.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }

    public static class Builder {

        BasicParamsInterceptor interceptor;

        public Builder() {
            interceptor = new BasicParamsInterceptor();
        }

        public Builder addParam(String key, String value) {
            interceptor.paramsMap.put(key, value);
            return this;
        }

        public Builder addParamsMap(Map paramsMap) {
            interceptor.paramsMap.putAll(paramsMap);
            return this;
        }

        public Builder addHeaderParam(String key, String value) {
            interceptor.headerParamsMap.put(key, value);
            return this;
        }

        public Builder addHeaderParamsMap(Map headerParamsMap) {
            interceptor.headerParamsMap.putAll(headerParamsMap);
            return this;
        }

        public Builder addHeaderLine(String headerLine) {
            int index = headerLine.indexOf(":");
            if (index == -1) {
                throw new IllegalArgumentException("Unexpected header: " + headerLine);
            }
            interceptor.headerLinesList.add(headerLine);
            return this;
        }

        public Builder addHeaderLinesList(List headerLinesList) {
            for (String headerLine: headerLinesList) {
                int index = headerLine.indexOf(":");
                if (index == -1) {
                    throw new IllegalArgumentException("Unexpected header: " + headerLine);
                }
                interceptor.headerLinesList.add(headerLine);
            }
            return this;
        }

        public Builder addQueryParam(String key, String value) {
            interceptor.queryParamsMap.put(key, value);
            return this;
        }

        public Builder addQueryParamsMap(Map queryParamsMap) {
            interceptor.queryParamsMap.putAll(queryParamsMap);
            return this;
        }

        public BasicParamsInterceptor build() {
            return interceptor;
        }

    }
}
Activity/Fragment 中的调用

1. 创建 Loader 实例

mGankLoader = new GankLoader();

2. 通过 Loader 调用方法获取结果

private void getGankList(){
        Subscription subscription = mGankLoader.getGankList().subscribe(new Action1() {
            @Override
            public void call(List gankEntries) {
                Log.d("TAG","gank size:"+gankEntries.size());
                mAdapter.setData(gankEntries);
                mAdapter.notifyDataSetChanged();
            }
        }, new Action1() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        });

        addSubscription(subscription);
    }

3. GankLoader.java

/**
 * Created on 2022/3/18 10:50
 *
 * @author Gong Youqiang
 */
public class GankLoader extends ObjectLoader {
    private GankService mGankService ;
    public GankLoader(){
        mGankService = RetrofitServiceManager.getInstance().create(GankService.class);
    }

    /**
     * 获取干货列表0
     * @return0
     */
    public Observable getGankList(){
        return observe(mGankService.getGank("1","10")).map(new Func1() {
            @Override
            public List call(GankResp gankResp) {
                return gankResp.result;
            }
        });
    }

}

4. GankService.java

/**
 * Created on 2022/3/18 10:51
 *
 * @author Gong Youqiang
 */
public interface GankService {
    /**
     *
     * @param
     * @param
     * @return
     */
    @FormUrlEncoded
    @POST("getWangYiNews")
    Observable getGank(@Field("page") String page, @Field("count") String count);
}

5. 数据类

/**
 * Created on 2022/3/18 10:51
 *
 * @author Gong Youqiang
 */
public class GankResp implements Serializable {

    @SerializedName("code")
    public Integer code;
    @SerializedName("message")
    public String message;
    @SerializedName("result")
    public List result;

}

-------------------------------------------------
/**
 * Created on 2022/3/18 10:41
 *
 * @author Gong Youqiang
 */
public class GankEntry implements Serializable {
    @SerializedName("path")
    public String path;
    @SerializedName("image")
    public String image;
    @SerializedName("title")
    public String title;
    @SerializedName("passtime")
    public String passtime;
}

以上就是封装的全部内容,还没有用 Retrofit 的,赶快用上它来改造你想网络请求库吧!!!

关注
打赏
1658837700
查看更多评论
立即登录/注册

微信扫码登录

2.0490s