Jetpack之LiveData

313 阅读4分钟

LiveData 是一个持有数据的类,它持有的数据是可以被观察者订阅的,当数据被修改时就会通知观察者。观察者可以是 Activity、Fragment、Service 等。 首先看它的使用,一种方式我们已经用过了,即与ViewModel一起使用,这里就不在赘述,另一种方式是直接继承LiveData。比如实现wifi信号值的监听

class WifiLiveData private constructor(context: Context) : LiveData<Int>() {

    private var mContext: WeakReference<Context> = WeakReference(context)

    companion object {

        private var instance: WifiLiveData? = null

        fun getInstance(context: Context): WifiLiveData {
            if (instance == null) {
                instance = WifiLiveData(context)
            }
            return instance!!
        }
    }

    override fun onActive() {
        super.onActive()
        registerReceiver()
    }

    override fun onInactive() {
        super.onInactive()
        unregisterReceiver()
    }

    /**
     * 注册广播,监听 Wifi 信号强度
     */
    private fun registerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
        mContext.get()!!.registerReceiver(mReceiver, intentFilter)
    }

    /**
     * 注销广播
     */
    private fun unregisterReceiver() {
        mContext.get()!!.unregisterReceiver(mReceiver)
    }

    private val mReceiver = object : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent) {
            when (intent.action) {
                WifiManager.RSSI_CHANGED_ACTION -> getWifiLevel()
            }
        }
    }

    private fun getWifiLevel() {
        val wifiManager = mContext.get()!!.applicationContext.getSystemService(android.content.Context.WIFI_SERVICE) as WifiManager
        val wifiInfo = wifiManager.connectionInfo
        val level = wifiInfo.rssi

        instance!!.value = level // 发送 Wifi 的信号强度给观察者
    }
}

因为LiveData 能够感知观察者的生命周期,只有当观察者处于激活状态(STARTED、RESUMED)才会接收到数据更新的通知,在未激活时会自动解注册观察者,以减少内存泄漏。所以继承LiveData时需要实现onActive及onInactive方法。那么上面最重要的就是这两个方法了,那么又是如何将值通知给观察者的呢,这里就看最后一行代码其实调用的是LiveData中的setValue方法,这与之前的ViewModel中的使用(postValue)其实是一样的。之前在viewModel中使用的MutableLiveData其实也是继承了LiveData,他的实现如下

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

使用时还利用上节中的ViewModel所使用的activity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
//        获取factory
        val factory: ViewModelProvider.Factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application)
//        获取provider
        val provider = ViewModelProvider(this, factory)
//        获取viewModel
        val mViewModel=provider.get(UserViewModel::class.java)
//        观察viewModel的变化来更新UI
        mViewModel.getUsers().observe(this, Observer {
            Log.e(javaClass.simpleName,it.toString())
        })

        withExtendsLiveDataTest()
    }
    private fun withExtendsLiveDataTest() {
        WifiLiveData.getInstance(this).observe(this, Observer {
            Log.e("MainActivity", it.toString()) // 观察者收到数据更新的通知,打印 Wifi 信号强度
        })
    }


}

可以看到无论是使用MutableLiveData还是自己继承LiveData,最终都是要调用LiveData的observe方法。那么我们就从observe方法开始。

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        //必须在主线程观察
        assertMainThread("observe");
        //如果当前的activity或者fragment已经destroy了,那么就停止观察
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //将observer和lifecycleOwner封装到一起
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //判断observer是否有与之关联的wrapper
        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;
        }
        //这就跟之前的监听lifecycle一样了
        owner.getLifecycle().addObserver(wrapper);
    }
}

这里需要重点看一下这个wrapper,它是LiveData的内部类

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

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super 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);
    }
}

在activity或者fragment的生命周期发生变化时会回调其中的onStateChanged方法。若当前处于 DESTROYED 状态,则会移除观察者;若当前处于激活状态,则会调用 activeStateChanged() 方法。activeStateChanged() 方法位于父类 ObserverWrapper 中。

void activeStateChanged(boolean newActive) {
    //新旧状态一致则返回
    if (newActive == mActive) {
        return;
    }
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {//激活状态的observer个数从0到1
        onActive();//空实现,子类复写
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {//激活状态的observer个数从1到0
        onInactive();//空实现,子类复写
    }
    if (mActive) {//如果是激活态的话,向观察者发送LiveData
        dispatchingValue(this);
    }
}

最后看dispatchingValue

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    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);
    mDispatchingValue = false;
}

可以看到这里有两层判断,如果ObserverWapper不为空则直接notify,如果为空的话就遍历map,notify每一个观察者,那么最终的通知方法即为considerNotify,在这里面最终调用 observer.mObserver.onChanged((T) mData); 这就是我们在activity或者fragment中得到的数据。上面的整个流程是从activity生命周期变化的过程来执行的顺序。当然之前举例的两种方式使用时,与ViewModel一起使用时用到了postValue,而wifi强度监听时则采用了setValue的方式来通知观察者。它们的实现如下

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

setValue必须在主线程调用,这里看到dispatchingValue中的ObserverWrapper为null,所以这里他就会去通知所有的观察者。而Post则是将子线程的数据推送到主线程

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

也就是说将这个Runnable发到主线程,post的具体实现为

@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
                mMainHandler = new Handler(Looper.getMainLooper());
            }
        }
    }
    //noinspection ConstantConditions
    mMainHandler.post(runnable);
}

上面的postRunnable实现也很简单

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

其实就是在主线程调用setValue方法