前言
Retrofit算是目前最流行的網絡框架了,而用的比較多的組合方式是Rxjava+Retrofit,因爲RxJava很好的實現了異步通信、UI線程和子線程之間的切換,但是RxJava+Retrofit這一組合有一個缺點,那就是容易造成內存泄漏,因爲不能感知UI的生命週期,當然通過加入RxLifeCycle也能解決這一問題。我們今天要說的不是RxLifeCycle,主角是LiveData,下面進入主題。
我們先看LiveData+Retrofit封裝,再做分析
LiveData+Retrofit封裝
1.添加依賴庫
//retrofit
api 'com.squareup.retrofit2:retrofit:2.1.0'
//okhttp
api 'com.squareup.okhttp3:okhttp:3.5.0'
//日誌
api 'com.squareup.okhttp3:logging-interceptor:3.6.0'
api 'com.squareup.retrofit2:converter-gson:2.1.0'
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.0"
// alternatively, just LiveData
implementation "android.arch.lifecycle:livedata:1.1.0"
2.BaseRetrofit
import android.support.annotation.NonNull;
public interface RetrofitWrapper<T> {
/**
* retrofit初始化
*/
void initRetrofit(@NonNull Class<T> tClass);
/**
* 獲取http api接口
* @return
*/
T getService();
}
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class BaseRetrofit<T> implements RetrofitWrapper<T> {
private static final String TAG = "BaseRetrofit";
private String url;
private Retrofit retrofit;
private Class<T> tClass;
private T service;
public BaseRetrofit(Class<T> tClass, String url){
this.tClass = tClass;
this.url = url;
initRetrofit(tClass);
}
@Override
public void initRetrofit(Class<T> tClass) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())
.build();
if (!url.endsWith("/")){
url += "/";
}
//創建retrofit實例
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.baseUrl(url)
.build();
//創建請求接口實例
service = retrofit.create(tClass);
}
@Override
public T getService() {
if (null == service){
service = retrofit.create(tClass);
}
return service;
}
}
3.LiveDataCallAdapterFactory
import android.arch.lifecycle.LiveData;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
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);
Type rawType = getRawType(observableType);
if (rawType != ApiResponse.class){
throw new IllegalArgumentException("type must be ApiResponse");
}
if (!ParameterizedType.class.isInstance(observableType)){
throw new IllegalArgumentException("resource must be Parameterized");
}
return new LiveDataCallAdapter<Type>(observableType);
}
}
其中ApiResponse是請返回的數據結構,一般都是code+msg+data
4.LiveDataCallAdapter
import android.arch.lifecycle.LiveData;
import java.lang.reflect.Type;
import java.util.concurrent.atomic.AtomicBoolean;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Callback;
import retrofit2.Response;
public class LiveDataCallAdapter<T> implements CallAdapter<LiveData<T>> {
private static final String TAG = LiveDataCallAdapter.class.getSimpleName();
private Type responseType;
public LiveDataCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return null;
}
@Override
public <R> LiveData<T> adapt(final Call<R> call) {
return new LiveData<T>(){
AtomicBoolean start = new AtomicBoolean(false);
@Override
protected void onActive() {
super.onActive();
if (start.compareAndSet(false, true)){
call.enqueue(new Callback<R>() {
@Override
public void onResponse(Call<R> call, Response<R> response) {
if (200 == response.code()) {
postValue((T) response.body());
}else {
ApiResponse apiResponse = new ApiResponse(response.code(), response.message(), response.errorBody());
postValue((T) apiResponse);
}
}
@Override
public void onFailure(Call<R> call, Throwable t) {
Log.e(TAG, t.getMessage());
if (responseType == ApiResponse.class){
ApiResponse apiResponse = new ApiResponse(-1, t.getMessage(), null);
postValue((T) apiResponse);
}
}
});
}
}
};
}
}
5.創建api請求接口
import android.arch.lifecycle.LiveData;
import java.util.List;
import retrofit2.http.GET;
public interface BusinessService {
@GET("banner/json")
LiveData<ApiResponse<List<BannerVo>>> bannerList();
}
原理剖析
以上就是LiveData+Retrofit完整封裝,可以發現與之前Retrofit+RxJava封裝對比,除了適配器不一樣,Retrofit部分基本一樣。不知道大家有沒有看到LiveDataCallAdapter中有一行關鍵代碼:postValue();
而這行代碼的作用是通過LiveData將請求結果發送到主線程(UI線程)
那麼LivaData是如何感知Activity或Fragment生命週期進而防止內存泄漏的呢?我們繼續看LiveData源碼,發現有下面一段代碼:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
在onStateChanged回調中,判斷當前狀態是銷燬狀態時,會移除Observer
/**
* Removes the given observer from the observers list.
*
* @param observer The Observer to receive events.
*/
@MainThread
public void removeObserver(@NonNull final Observer<T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
那又是在什麼時候如何訂閱的呢?是在相應的activity或fragment中調用LiveData下面方法訂閱,訂閱之後就可以感知對應的生命週期了。
/**
* Adds the given observer to the observers list within the lifespan of the given
* owner. The events are dispatched on the main thread. If LiveData already has data
* set, it will be delivered to the observer.
* <p>
* The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
* or {@link Lifecycle.State#RESUMED} state (active).
* <p>
* If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
* automatically be removed.
* <p>
* When data changes while the {@code owner} is not active, it will not receive any updates.
* If it becomes active again, it will receive the last available data automatically.
* <p>
* LiveData keeps a strong reference to the observer and the owner as long as the
* given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
* the observer & the owner.
* <p>
* If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
* ignores the call.
* <p>
* If the given owner, observer tuple is already in the list, the call is ignored.
* If the observer is already in the list with another owner, LiveData throws an
* {@link IllegalArgumentException}.
*
* @param owner The LifecycleOwner which controls the observer
* @param observer The observer that will receive the events
*/
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
總結:1.LiveDate+Retrofit封裝只需在addCallAdapterFactory方法中加入LiveDataCallAdapter即可;
2.通過LiveData的observer方法訂閱之後即可感知相應生命週期;
3.在activity或fragment銷燬時移除observer達到防止內存泄漏的作用。