-
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 的,赶快用上它来改造你想网络请求库吧!!!