AAC学习笔记LiveData(一)

本文为《Android Architecture Components学习笔记》的一部分
水平有限,如有不当之处请不吝赐教

可参考:
https://developer.android.google.cn/topic/libraries/architecture/livedata#use_livedata_with_room
使用LiveData的优点:

  • 确保UI与数据更新一致
    LiveData遵循观察者模式。当生命周期状态改变时,LiveData作为被观察者会通知Observer对象中的UI执行更新。这样可以方便、集中的更新UI,而不需要逐个实现UI更新事件。

  • 防止内存泄漏
    当关联到Lifecycle对象的生命周期处于销毁状态时,被绑定到观察者的对象可自行清理。

  • Activity停止后不会导致崩溃
    如果观察者生命周期处于非活动状态,例如在回退栈中的Activity,则它不会收到任何关于LiveData的事件。

  • 不需要更多的手动生处理命周期
    生命周期状态由LiveData自动管理,无需手动实现。

  • 自动获取最新数据
    如果生命周期变为活动状态,它将收到最新数据。例如,后台活动在返回到前台后立即收到最新数据。

  • 保持数据一致性
    重新创建Activity或Fragment(如设备旋转)时,它会立即收到最新的可用数据。

  • 共享资源
    可以用LiveData单例模式包装系统服务,从而可以在app中共享。LiveData对象仅需连接到系统服务,其他需要该资源的观察者都可获得数据。

我觉学习LiveData会有三个收获:观察者模式、自动更新、生命周期。


观察者模式

关于观察者模式也许并不陌生。这里我们来看看LiveData的观察者模式是怎么实现的。

为了方便理解,我模拟了一套LiveData类,分别是:MyObserver、MyLiveData、MyMediatorLiveData、MyMutableLiveData。它们都是系统类名字前加了My,结构、成员名都是按照系统类的定义。

模拟的Observer类,名字为MyObserver:

public interface MyObserver<T> {
    void onChanged(@Nullable T t);
}

注意:LiveData使用的Observer是android.arch.lifecycle包的。

模拟的LiveData类,名字叫MyLiveData:

//包含了LIveData核心的成员。名称都与LiveData保持一致,数据类型也基本相同。
public class MyLiveData<T> {
    private static final Object NOT_SET = new Object();
    //自己的数据
    private volatile Object mData = NOT_SET;
    //放观察者的map
    private SafeIterableMap<MyObserver<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

    //通知变更,也就是执行观察者的onChanged()方法
    private void considerNotify(ObserverWrapper observer) {
        observer.mObserver.onChanged((T) mData);
    }
	//调度值变更,当LiveData数据发生改变时,通过此方法遍历观察者以执行其onChanged()方法
    private void dispatchingValue() {
        for (@SuppressLint("RestrictedApi")
             Iterator<Map.Entry<MyObserver<T>, ObserverWrapper>> iterator =
             mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
            considerNotify(iterator.next().getValue());
        }
    }
    //注册观察者
    public void observe(@NonNull MyObserver<T> observer) {
        ObserverWrapper wrapper = new ObserverWrapper(observer);
        //将观察者放入mObservers
        mObservers.putIfAbsent(observer, wrapper);
    }

    public void removeObserver(@NonNull final MyObserver<T> observer) {mObservers.remove(observer); }
	
	//改变数据
    public void setValue(T value) {
        mData = value;
        dispatchingValue();
    }

    //对Observer的包装类型
    private class ObserverWrapper {
        final MyObserver<T> mObserver;
        ObserverWrapper(MyObserver<T> observer) {
            mObserver = observer;
        }
    }

}

Kotlin实现的MyLiveData:

class MyLiveData<T> {
    val NOT_SET = Object()
    @Volatile
    var mData = NOT_SET as T

    var mObservers = SafeIterableMap<MyObserver<T>, ObserverWrapper>()

    fun considerNotify(observer: ObserverWrapper): Unit {
        observer.mObserver.onChanged(mData as T)
    }

    fun dispatchingValue() {
        for (iterator in mObservers.iteratorWithAdditions())
            considerNotify(iterator.value)
    }

    fun observe(observer: MyObserver<T>) {
        var wrapper = ObserverWrapper(observer)
        mObservers.putIfAbsent(observer, wrapper)
    }

    fun removeObserver(observer: MyObserver<T>) {
        mObservers.remove(observer)
    }

    fun setValue(value: T) {
        mData = value
        dispatchingValue()
    }

    inner class ObserverWrapper(val mObserver: MyObserver<T>)
}

Kotlin写的有没有清爽很多的感觉。
自己的数据通过mData成员保存。mObservers就是保存观察者的map了(不要纠结这个map的类型,现在就把他当成个普通的map就可以了)。
基本原理:

  • 通过observe()方法将观察者放入mObservers
  • 通过setValue()方法更改数据,然后调用dispatchingValue()方法;
  • dispatchingValue()方法,遍历mObservers并逐条执行观察者的onChange()方法;

说到这里,可以对比一下LiveData类了,基本原理就是这样。我们来试试好不好用:

public class MainActivity extends AppCompatActivity {

    //MyLiveData类型的数据
    MyLiveData<String> mString= new MyLiveData<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
        *添加了三个观察者
        */
        mString.observe(new MyObserver<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                //在这里写数据变更时的处理代码
                Log.d("myStep1","观察者1:"+s);
            }
        });
        mString.observe(s -> {
            //在这里写数据变更时的处理代码
            Log.d("myStep1", "观察者2:" + s);
        });
        mString.observe(s -> Log.d("myStep1", "观察者3:"+s));

        //变更数据
        mString.setValue("我来了");
    }
}

上面的代码注册了三个观察者,当setValue()时都执行了自己的onChange()
我用了三种写法实现了三个观察者,效果都一样。我觉得还是lambda方便。

Kotlin实现的MainActivity:

class MainActivity : AppCompatActivity() {

    var mString: MyLiveData<String> = MyLiveData()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        mString.observe(MyObserver { Log.d("观察者1:", it) })
        mString.observe(MyObserver { Log.d("观察者2:", it) })
        mString.observe(MyObserver { Log.d("观察者3:", it) })

        mString.setValue("我来了")

注意:Java写的MyObserver,才可以用采用上面的传递方式
否则会报错


自动更新

稍微对app结构有要求的场景都需要分层,那么分层后的解耦就很关键。LiveData有个非常适用的特性就是可以给自己增加源,当源发生改变时,会执行更新自己的操作。这就好比各个对象形成了一个链条,当源头改变时,可以一节一节的将改变传输下去,每个节点可自由定义处理更新的方法。

模拟的MediatorLiveData,名字为MyMediatorLiveData

public class MyMediatorLiveData<T> extends MyMutableLiveData<T> {
	//存放数据源的map
    private SafeIterableMap<MyLiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
	//添加数据来源,当然源也必须是LiveData
    public <S> void addSource(@NonNull MyLiveData<S> source, @NonNull MyObserver<S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        mSources.putIfAbsent(source, e);
        e.plug();//将自己作为观察者,插入到源的观察者map中
    }

    public <S> void removeSource(@NonNull MyLiveData<S> toRemote) {
        Source<?> source = mSources.remove(toRemote);
        if (source != null) {
            source.unplug();
        }
    }

    private static class Source<V> implements MyObserver<V> {
        final MyLiveData<V> mLiveData;
        final MyObserver<V> mObserver;

        Source(MyLiveData<V> liveData, final MyObserver<V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }
		/**
		*将自己作为观察者,插入到源的观察者map中。
		*在MediatorLiveData里使用的是observeForever(),后面会详细说
		*/
        void plug() { mLiveData.observe(this); }
		//在源里移除自己
        void unplug() {mLiveData.removeObserver(this);}
		//当源发生变化时,执行自己定义的onChanged()
        public void onChanged(@Nullable V v) {
            mObserver.onChanged(v);
        }
    }
}

这里要说明的最重要机制是内部类Source(MyLiveData<V> liveData, final MyObserver<V> observer)

  • liveData:来源数据
  • observer:自己定义的观察者以及当来源数据发生改变的时候执行的onChange()
  • plug():在源上注册自己的观察者

本节内容,说白了就是把自己当成观察者注册到LiveData类型里。当源数据发生改变,执行自己定义的onChange()改变自己。

模拟的MutableLiveData,名字为MyMutableLiveData

public class MyMutableLiveData<T> extends MyLiveData<T> {
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

来看模拟的效果:

public class MainActivity extends AppCompatActivity {

    MyMediatorLiveData<String> mString= new MyMediatorLiveData<>();
    MyLiveData<String> mSource= new MyLiveData<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //注册观察者
        mString.observe(s -> Log.d("myStep2", "1:" + s));
        mString.observe(s -> Log.d("myStep2", "2:" + s));
        mString.observe(s -> Log.d("myStep2", "3:" + s));
        
        //将自己的setValue()作为onChange()包装成自己的observer,执行添加源操作
        mString.addSource(mSource,mString::setValue);
        mSource.setValue("我来了");
    }
}

这就好比各个LiveData可以环环相扣像链条一样组装起来(中间环节必须是MediatorLiveData)。在链条每节进行addSource()时,通过Observer参数里定义onChanged(),可以对中间数据进一步加工。所以会有一个MediatorLiveData。链条的每节在setValue()时,都会将变更传递到下一环节。

更新控制

有关更新控制首先用到的是LiveData的mVersion,我们来修改一下MyLiveData:
添加:

	static final int START_VERSION = -1;
	private int mVersion = START_VERSION;

在MyLiveData的setValue()添加控制变量:

    public void setValue(T value) {
        //每次更新都会增加版本号,但并没有提供更新失败的处理
        mVersion++;
        mData = value;
        dispatchingValue();
    }

修改MyLiveData的considerNotify()

    private void considerNotify(ObserverWrapper observer) {
        //检查观察者版本,如果大于自身版本,则不会再onChanged()
        if (observer.mLastVersion >= mVersion) {return;}
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

MyLiveData增加getVersion()

    int getVersion() {
        return mVersion;
    }

MyMediatorLiveData的Source增加int mVersion = START_VERSION;
修改MyMediatorLiveData的onChangend()

        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                //更新版本信息,也就是说如果执行onChange的时候会改变版本与被源一致
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }

更新控制仅仅是控制了更新次数,而一旦执行了更新,无论结果如何版本都将强制保持一致。


总结一下

MyObserver是观察者接口,注册观察者需要实现这个接口。
MyLiveData、MyMutableLiveData、MyMediatorLiveData使用它们包装的数据类型,作为被观察者类(或内容、订阅)。
MyMutableLiveData继承自MyLiveData,表示可变的LiveData类型。
MyMediatorLiveData继承自MyMutableLiveData,表示中介类型。

本篇模拟了LiveData观察者模式的实现机制。但是少了一个重量级因素:与生命周期相关

猜你喜欢

转载自blog.csdn.net/jouter/article/details/83538531