探究LiveData

256 阅读4分钟

发现问题

初识livedata,想在项目中用着试试,于是尝试了个demo:

  1. 先定义retrofit接口ApiLibService:用来获取此接口(www.weather.com.cn/data/cityin…) 的天气数据
interface ApiLibService {
    @Headers("Content-Type: application/json", "Content-Encoding: gzip")
    @GET("/data/cityinfo/101010100.html")
    fun weather(): LiveData<ApiResponse<WeatherResult>>
}

ApiResponse是对返回结果的封装,本身是个sealed类

  1. 用repository类引用他:
class HomeRepository @Inject constructor(
        private val apiLibService: ApiLibService
){
    fun getWeather(): LiveData<Resource<WeatherResult>> = apiLibService.weather().asResource()
}

ApiLibService是由dagger注入
asResource为自定义LiveData扩展方法,其作用是将ApiResponse封装转化为Resoure封装,Resouce维护了success,error和loading三个状态

3.再由viewmodel调用repository,在fragment中调用viewmodel

class HomeViewModel @Inject constructor(
        private val repository: HomeRepository
) : ViewModel(){
    private val _textNet = MutableLiveData<String>()
    val textNet = _textNet
    fun getWeather() {
        repository.getWeather().map {
            if(it.status == Status.SUCCESS) {
                val data = it.data?.weatherinfo
                _textNet.postValue(data.toString())
            } else {
                _textNet.postValue(it.message)
            }
        }
    }
}

class HomeFragment : Fragment() , Injectable {
    private lateinit var homeViewModel: HomeViewModel
    @Inject
    lateinit var factory: MyViewModelFactory
      override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
       homeViewModel = ViewModelProviders.of(this, factory).get(HomeViewModel::class.java)
    }

   override fun onActivityCreated(savedInstanceState: Bundle?) {
        homeViewModel.textNet.observe(viewLifecycleOwner, Observer {
            text_home.text = "$it"
        })
        homeViewModel.getWeather()
   }
}

repository也同样是dagger的注入,map为Transformations中的map方法
由fragment调用viewmodel的getWeather方法,通常的思路就是能触发epository.getWeather()并一步步执行下去,返回resource结果,由_textNet这个livedata通知到fragment的text_home更新
但事实是什么都没发生
说明livedata必然有observer才会触发:
于是这样修改:

fun getWeather(lifecycleOwner : LifecycleOwner) {
        repository.getWeather().observe(lifecycleOwner, Observer {
            if(it.status == Status.SUCCESS) {
                val data = it.data?.weatherinfo
                _textNet.postValue(data.toString())
            } else {
                _textNet.postValue(it.message)
            }
        })
    }

调用则改为:

homeViewModel.getWeather(lifecycleOwner = viewLifecycleOwner)

这样就正常了
详细代码可以移步这里:github.com/robinfjb/An…

源码探究:

首先来看下observe方法:

public abstract class LiveData<T> {
     @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        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);
    }
}

生成一个新的LifecycleBoundObserver(ObserverWapper)对象,将observer为key,ObserverWapper对象为value放在名为mObservers的map中,并将其加入到生命周期观察中去

分析下LifecycleBoundObserver :

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
...
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
...
}

实现了LifecycleEventObserver接口,一旦生命周期发生变化,则会调用onStateChanged方法,看下activeStateChanged的实现,在父类ObserverWrapper中:

      void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }

最后一句代码,如果mActive=true则会调用dispatchingValue方法,mActive在LifecycleBoundObserver中的实现为lifecycle值为STARTED或以上,换一句话说,只要是组件调用onStart或者onResume就会触发

dispatchingValue的代码:

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
       ...
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
       ...
    }

又会调用LiveData的considerNotify方法:

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

这里又会检查下shouldBeActive方法
这里有个关键点,会比较版本号,如果版本号没更新则不会通知onChanged
mVerison在LiveData有参构造中设置为0,无参构造函数中设置为-1,在setValue中自增+1

  static final int START_VERSION = -1;
 public LiveData(T value) {
        ...
        mVersion = START_VERSION + 1;
    }

  public LiveData() {
        ...
        mVersion = START_VERSION;
    }

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

同样,调用setValue也会触发dispatchingValue,但此处传入的参数是null,dispatchingValue中会遍历mObservers找到对应的ObserverWapper,所以如果没有注册过ObserverWapper,则不会发生任何事

线程切换

在上述例子中,我们通过LiveDataCallAdapter来实现了retrofit的Call转LiveData:

lass LiveDataCallAdapter<R>(private val responseType: Type) :
    CallAdapter<R, LiveData<ApiResponse<R>>> {

    override fun responseType() = responseType

    override fun adapt(call: Call<R>): LiveData<ApiResponse<R>> {
        return object : LiveData<ApiResponse<R>>() {
            private var started = AtomicBoolean(false)
            override fun onActive() {
                super.onActive()
                if (started.compareAndSet(false, true)) {
                    call.enqueue(object : Callback<R> {
                        override fun onResponse(call: Call<R>, response: Response<R>) {
                            postValue(ApiResponse.create(response))
                        }

                        override fun onFailure(call: Call<R>, throwable: Throwable) {
                            postValue(ApiResponse.create(throwable))
                        }
                    })
                }
            }
        }
    }
}

在此调用的是LiveData中的postValue方法,将net的线程转为main线程
看下postValue中如何实现线程切换:

protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

代码很简单,用ArchTaskExecutor类来实现postToMainThread,这个类是androidx包下的多线程包装类, postToMainThread的实现主要是具有MainLooper的Handler来实现,
mPostValueRunnable:

private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

用同一个对象锁mDataLock实现数据同步,并将mPendingData置为初始状态,保证只运行一次,最终调用setValue方法

综上所诉,LiveData的代码实现还是比较简单明朗,LiveData 的特点在于它是一个可感知生命周期的观察者模式,重点是观察者模式与普通思维的不同