Android 網絡框架(三)LiveData+Retrofit封裝與原理剖析

前言

       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 &amp; 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達到防止內存泄漏的作用。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章