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 {

    /**
     * retrofit初始化
     */
    void initRetrofit(@NonNull Class 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 implements RetrofitWrapper {
    private static final String TAG = "BaseRetrofit";
    private String url;
    private Retrofit retrofit;
    private Class tClass;
    private T service;

    public BaseRetrofit(Class tClass, String url){
        this.tClass = tClass;
        this.url = url;
        initRetrofit(tClass);
    }

    @Override
    public void initRetrofit(Class 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(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 implements CallAdapter> {
    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  LiveData adapt(final Call call) {
        return new LiveData(){
            AtomicBoolean start = new AtomicBoolean(false);
            @Override
            protected void onActive() {
                super.onActive();
                if (start.compareAndSet(false, true)){
                    call.enqueue(new Callback() {
                        @Override
                        public void onResponse(Call call, Response 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 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>> bannerList();
}

原理剖析

以上就是LiveData+Retrofit完整封装,可以发现与之前Retrofit+RxJava封装对比,除了适配器不一样,Retrofit部分基本一样。不知道大家有没有看到LiveDataCallAdapter中有一行关键代码:postValue();

Android 网络框架(三)LiveData+Retrofit封装与原理剖析_第1张图片

而这行代码的作用是通过LiveData将请求结果发送到主线程(UI线程)

Android 网络框架(三)LiveData+Retrofit封装与原理剖析_第2张图片

那么LivaData是如何感知Activity或Fragment生命周期进而防止内存泄漏的呢?我们继续看LiveData源码,发现有下面一段代码:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer 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 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.
 * 

* The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED} * or {@link Lifecycle.State#RESUMED} state (active). *

* If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will * automatically be removed. *

* 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. *

* 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. *

* If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData * ignores the call. *

* 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 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达到防止内存泄漏的作用。

 

下面是我个人公众号,欢迎关注

Android 网络框架(三)LiveData+Retrofit封装与原理剖析_第3张图片

 

你可能感兴趣的:(Android)