您的位置:首页 > 其它

Retrofit自定义CallAdapterFactory

2018-01-26 14:45 393 查看
retrofit自从面世,一直很火,现在大多android开发的都在用的网络框架。我们在设置retrofit的时候需要设置CallAdapterFactory

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.stonebangbang.com/test.php/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.creat())

.build();
return retrofit.create(apiServiceClass);



这是用rxjava自定义的adapter来实现的,我们一般都是这么用,但是如果我们要自定义calladapter的时候该怎么做呢?

现在我们来看看calladapter是干什么的

abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);

/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}

/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
这是一个抽象类,我们需要实现get方法,先来看看这几个方法都是干嘛的。

getParameterUpperBound[/code]
首先getParameterUpperBound方法,他是获取参数的type的,我觉得可以把它理解为获取的泛型,比如我们写了个User<T>,

我们可以new User<Man>这个man就是我们实例化的type。在看这个方法,他有两个参数,一个是index,是指位置,比如我们的User<T,V>   这个T就是0,这个V就是1,parameterizedType是个接口,继承type接口,从字面上来看是参数类型,所以我把它理解为我们定义的这个T的类型,比如man,比如我们传入的任何实例,如果我们没有传入那就不是parameterizedtype类型的。

而getRawType是提取的实例class,如果我们的User<T> 他得到的就是User.class。

而get方法是返回一个calladapter,所以我们要顶一个calladatper,再来看下calladapter,

public interface CallAdapter<R, T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
* <p>
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();

/**
* Returns an instance of {@code T} which delegates to {@code call}.
* <p>
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async<R>} which invoked {@code call} when run.
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
*   return Async.create(new Callable<Response<R>>() {
*     @Override
*     public Response<R> call() throws Exception {
*       return call.execute();
*     }
*   });
* }
* </code></pre>
*/
T adapt(Call<R> call);


它是个接口,有两个方法,一个是responseType,这个就是从网络获取数据response的类型,也就是我们gson活着fastjson需要解析用到的那个type,这个很重要,如果这个传错了,那我们用gson解析json成model的时候就会报错。

adapt就是返回的实例,类似于我们写service的那个observable.

好了基本内容介绍完了,现在写个实例吧,retrofit adapter已经写了一个实例,大家可以做参考,不过我们自己实现的话,其实不用那么复杂。

public class LiveDataCallAdapterFactory extends CallAdapter.Factory {

@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != LiveData.class) {
return null;
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
Timber.d("rawObservableType = " + rawObservableType.getSimpleName());
if (rawObservableType != ResponseData.class) {
throw new IllegalArgumentException("type must be a resource");
}
if (! (observableType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resource must be parameterized");
}
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
Timber.d("bodyType = " + bodyType.toString());
return new LiveDataCallAdapter<>(observableType);
}
}

这是我对livedata实现的factory,很简单,getRawType和getParameterUpperBound方法已经在上面说过了,特别需要注意的是,return livedatacalladapter里面传入的type

observableType 是你写的service返回值里面的T,比如LiveData<Response<User>> 他代表的事这个Response<User>

bodyType 代表的事User,当然如果你不关心body的type这块可以忽略。

在看一下LiveDataCallAdapter的写法


public class LiveDataCallAdapter<R> implements CallAdapter<R, LiveData<ResponseData>> {
private final Type responseType;
public LiveDataCallAdapter(Type responseType) {
this.responseType = responseType;
}

@Override
public Type responseType() {
return responseType;
}

@Override
public LiveData<ResponseData> adapt(Call<R> call) {
return new LiveData<ResponseData>() {
AtomicBoolean started = new AtomicBoolean(false);
@Override
protected void onActive() {
super.onActive();
if (started.compareAndSet(false, true)) {
call.enqueue(new Callback<R>() {
@Override
public void onResponse(Call<R> call, Response<R> response) {
Timber.d("success");
ResponseData responseData = new ResponseData<>();
if(response.isSuccessful()){
responseData = (ResponseData) response.body();
}else{
try {
responseData.setMessage(response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
responseData.setData(null);
responseData.setCode(response.code());
}
postValue(responseData);
}

@Override
public void onFailure(Call<R> call, Throwable throwable) {
ResponseData responseData = new ResponseData<>();
responseData.setCode(500);
responseData.setData(null);
responseData.setMessage(throwable.getMessage());
Timber.d(throwable," failure");
postValue(responseData);
}
});
}
}
};
}
}

responseType 就是刚才在factory里面传进来的,gson在解析的时候会用到这个type。

adpt非常简单,rxjava的事返回的object,更灵活一些,我们自己定义的话这块完全可以写死,想要response是什么这块就返回什么就可以了。我所以得网络请求返回的都是livedata<ResponseData> 所以这块我就直接写死了。Call是retrofit自带的。

responseData是我自己定义的一个类。

public class ResponseData<T> implements Serializable {

protected boolean success;
protected int code;

protected String message;

protected T date;

public boolean isSuccess() {
return true;

}
public void setSuccess(boolean success) {
this.success = success;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public T getData() {
return date;
}

public void setData(T data) {
this.date = data;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

请大神指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: