OkHttp + Retrofit应用示例。从引入依赖,编写接口,到发动网络申请。

引入依赖

引入依赖,应用Retrofit2。

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

查问 @Query

例如 URL https://base_url/backend-service/config?env=dev,问号前面属于查问内容。 不论是GET或POST,都要用@Query这个注解。否则会报异样。

URL填充与拼接

单纯 URL 填充能够用@Path注解。 例如上面这个post申请。

@POST("user-service/user/{uid}/token/refresh")Call<RefreshTokenResp> refreshToken(@Path("uid") String uid, @Query("token") String token);

GET带有查问的参数

public interface CfgService {    @GET("backend-service/config")    Call<ServerCfgResp> getServerCfg(@Query("env") String env);}

POST,带有查问的参数和body

public interface UserService {    @POST("user-service/login")    Call<LoginResp> login(@Query("lenovoST") String token, @Query("realm") String realm,                            @Body RequestBody body);    @POST("user-service/logout")    Call<CommonEntity> logout(@Query("token") String token, @Body RequestBody body);}

调用的时候要创立RequestBody;先考察好后盾承受的body类型。

Map<String, String> map = new HashMap<>();        map.put("system", "Android");        map.put("phoneBrand", Build.BRAND);        map.put("modelNum", Build.MODEL);        Gson gson = new Gson();        String bodyJson = gson.toJson(map);        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), bodyJson);

初始化OkHttpClient;这里信赖所有的SSL证书(正式环境不倡议这么做)。

private CfgService cfgService;    public void initService() {        SSLSocketFactory sslSocketFactory = null;        try {            sslSocketFactory = SSLUtils.getSSLSocketFactory();        } catch (Exception e) {            e.printStackTrace();        }        OkHttpClient.Builder builder = new OkHttpClient.Builder();        if (sslSocketFactory != null) {            Log.d(TAG, "sslSocketFactory != null");            builder.sslSocketFactory(sslSocketFactory);        } else {            Log.w(TAG, "sslSocketFactory == null");        }        builder.hostnameVerifier(new HostnameVerifier() {            @Override            public boolean verify(String hostname, SSLSession session) {                return true; // 强制返回true            }        });        OkHttpClient lenClient = builder.build();        Retrofit retrofit = new Retrofit.Builder()                .baseUrl(ServerCfg.HOST_URL)                .client(lenClient)                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .addConverterFactory(GsonConverterFactory.create())                .build();        cfgService = retrofit.create(CfgService.class);    }

调用网络申请

mNetworkManager.getUserApi().login(mLenovoToken, ServerCfg.RID, requestBody).enqueue(new Callback<LoginResp>() {            @Override            public void onResponse(Call<LoginResp> call, final Response<LoginResp> response) {                //...            }            @Override            public void onFailure(Call<LoginResp> call, final Throwable t) {                //...            }        });

信赖所有服务器的ssl

并不举荐这么做

public class SSLUtils {    /** * @return 信赖所有服务器 */    public static SSLSocketFactory getSSLSocketFactory() throws Exception {        SSLSocketFactory sslSocketFactory = null;        SSLContext sslContext = SSLContext.getInstance("TLS");        sslContext.init(null, new TrustManager[]{createTrustAllManager()}, new SecureRandom());        sslSocketFactory = sslContext.getSocketFactory();        return sslSocketFactory;    }    public static X509TrustManager createTrustAllManager() {        X509TrustManager tm = null;        try {            tm = new X509TrustManager() {                public void checkClientTrusted(X509Certificate[] chain, String authType)                        throws CertificateException {                    //do nothing,承受任意客户端证书                }                public void checkServerTrusted(X509Certificate[] chain, String authType)                        throws CertificateException {                    //do nothing,承受任意服务端证书                }                public X509Certificate[] getAcceptedIssuers() {                    return new X509Certificate[0];                }            };        } catch (Exception e) {        }        return tm;    }}

service 应用 io.reactivex.Observable

import io.reactivex.Observable; // 这个是rx2的包// ---    /** * 用户反馈接口 * * @param content 用户输出的反馈内容 */    @POST("feedbackAction")    Observable<UserFeedback> userFeedback(@Query("appVersion") String appVersion,                                          @Query("phoneModel") String phoneModel,                                          @Query("phoneOsVersion") String osVersion,                                          @Query("submitContent") String content);

示例 - Retrofit2,RxJava2

引入依赖

implementation 'com.squareup.retrofit2:retrofit:2.5.0'    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'    implementation 'io.reactivex.rxjava2:rxjava:2.2.8'

定义interface

import java.util.Map;import io.reactivex.Observable;import retrofit2.http.Field;import retrofit2.http.FieldMap;import retrofit2.http.FormUrlEncoded;import retrofit2.http.GET;import retrofit2.http.POST;import retrofit2.http.Query;/** * RustDrone后盾接口 * Created on 2019-5-17 */public interface RustDroneCommonService {    /** * 用户反馈接口 * * @param content 用户输出的反馈内容 */    @FormUrlEncoded    @POST("feedbackAction")    Observable<FeedbackResp> userFeedback(@Field("appVersion") String appVersion,                                          @Field("phoneModel") String phoneModel,                                          @Field("phoneOsVersion") String osVersion,                                          @Field("submitContent") String content,                                          @FieldMap Map<String, String> map);    /** * 获取手机验证码 * * @param mobile 手机号 */    @GET("verifyCode")    Observable<PhoneCodeResp> getPhoneCode(@Query("mobile") String mobile, @Query("oprType") int type);}

调用接口

import io.reactivex.Observer;import io.reactivex.android.schedulers.AndroidSchedulers;import io.reactivex.disposables.Disposable;import io.reactivex.schedulers.Schedulers;RustDroneDataCenter.getCenter().getCommonService().userFeedback(BuildConfig.VERSION_NAME,                    Build.MODEL.replace(" ", "-"), Build.VERSION.RELEASE, fd, ext)                    .subscribeOn(Schedulers.newThread())                    .observeOn(AndroidSchedulers.mainThread())                    .subscribe(new Observer<FeedbackResp>() {                        @Override                        public void onSubscribe(Disposable d) {//                            LL.dn(TAG, "onSubscribe: " + d);                        }                        @Override                        public void onNext(FeedbackResp feedbackResp) {                            LL.dn(TAG, "onNext: " + feedbackResp);                            if (feedbackResp.getCode() == 0) {                                popSubmitSuccessDialog();                            } else {                                LL.e("上传用户反馈失败");                                mPbLayout.setVisibility(View.GONE);                                popRetryDialog();                            }                        }                        @Override                        public void onError(Throwable e) {                            LL.e("上传用户反馈失败 code: " + e);                            mPbLayout.setVisibility(View.GONE);                            popRetryDialog();                        }                        @Override                        public void onComplete() {                            mPbLayout.setVisibility(View.GONE);                            LL.dn(TAG, "onComplete: 上传完结");                        }                    });

OkHttp 相干面试题:

1. 简述一下 OkHttp 的劣势

OkHttp 是一个十分优良的网络申请框架,已被谷歌退出到 Android 的源码中。目前比拟风行的 Retrofit 也是默认应用 OkHttp 的。

  • 易使用、易扩大。
  • 反对 HTTP/2 协定,容许对同一主机的所有申请共用同一个 socket 连贯。
  • 如果 HTTP/2 不可用, 应用连接池复用缩小申请提早。
  • 反对 GZIP,减小了下载大小。
  • 反对缓存解决,能够防止反复申请。
  • 如果你的服务有多个 IP 地址,当第一次连贯失败,OkHttp 会尝试备用地址。
  • OkHttp 还解决了代理服务器问题和SSL握手失败问题。

2. 讲一下 okhttp 的次要工作流程

第一步:创立 Request 和 OkHttpClicent 对象,而后将 Request 封装成 Call 对象,而后调用 enqueue() 办法执行异步申请;

第二步:Dispatcher 的 enqueue(AsyncCall) 和 promoteAndExecute() 办法,enqueue(AsyncCall) 有两个作用:一是增加 AsyncCall 到预执行队列 readyAsyncCalls,二是设置同一Host的连贯计数器;promoteAndExecute() 负责真正对 AsyncCall 进行资源的调度:对 readyAsyncCalls 进行迭代循环,如果正在执行的队列 size不超过 64 且同一Host 的连贯计数器的值不超过 5,就将这个申请放入到 runningAsyncCalls。而后遍历runningAsyncCalls,挨个执行外面的申请;

第三步:AsyncCall 对象把本人作为工作交到线程池执行,提交胜利后就 finish 掉;

3. OkHttp 的 Interceptor 类

官网:拦截器是 Okhttp 中提供的一种弱小机制,它能够实现网络监听、申请、以及响应重写、申请失败重试等性能。

  • RetryAndFollowUpInterceptor:重试和失败重定向拦截器
  • BridgeInterceptor:桥接拦截器,解决一些必须的申请头信息的拦截器
  • CacheInterceptor:缓存拦截器,用于解决缓存
  • ConnectInterceptor:连贯拦截器,建设可用的连贯,是 CallServerInterceptor 的根本
  • CallServerInterceptor:申请服务器拦截器将 http 申请写进 IO 流当中,并且从 IO 流中读取响应 Response

4. 请简述如何应用 OKHttp 发动网络申请?

应用 OKHttp 发动网络申请的步骤如下:

  • 新建 OKHttpClient
  • 依据申请的 URL 新建 Request 对象
    申请过程中所应用的参数放在 Request 对象的 RequestBody 中
  • 应用 Request 对象新建 Call 对象
  • 同步申请执行 call.execute(),异步申请执行 call.enqueue
  • 获取申请执行后果对象 Response 并解析

5. 如何应用 OKHttp 对 Cookie 进行解决?

应用OKHttp进行Cookie解决,有两种形式:

第一种是手动解决,在 callback 回调的 response 对象中,通过 response.headers() 能够获取所有头信息,包含 Cookie 信息。这时咱们能够将 Cookie 保留到本地,下次发动网络申请时再将 Cookie 信息加在头部。

第二种是应用 OKHttp 提供的 Cookjar,具体代码如下:

builder = new OkHttpClient.Builder();  builder.cookieJar(new CookieJar() {      private final HashMap<String, List<Cookie>> cookieStore = new HashMap<String, List<Cookie>>();        @Override      public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {          cookieStore.put(url.host(), cookies);      }        @Override      public List<Cookie> loadForRequest(HttpUrl url) {          List<Cookie> cookies = cookieStore.get(url.host());          return cookies != null ? cookies : new ArrayList<Cookie>();      }  });  okHttpClient = builder.build();  

其中,saveFromResponse() 会在接管服务器响应时执行,这时能够保留 Cookie 信息,loadForRequest() 会在发动网络申请时执行,这是能够增加已保留的 Cookie 信息。

6. OkHttp 对于网络申请都有哪些优化,如何实现的?

OKHttp 相比原生的 HttpUrlConnection 次要做了如下优化:

  • 反对HTTP2/SPDY
  • socket主动抉择最好路线,并反对主动重连
  • 领有主动保护的socket连接池,缩小握手次数,升高响应提早
  • 领有队列线程池,轻松写并发
  • 领有Interceptors轻松解决申请与响应(比方通明GZIP压缩,LOGGING)
  • 基于Headers的缓存策略,防止反复的网络申请

【Android开发:框架源码解析视频参考】