美文网首页
Android架构组件-LiveData

Android架构组件-LiveData

作者: _九卿_ | 来源:发表于2018-07-11 14:59 被阅读113次

    定义

    简单地说,LiveData是一个数据持有类。它具有以下特点:

    • 数据可以被观察者订阅;
    • 能够感知组件(Fragment、Activity、Service)的生命周期;
    • 只有在组件出于激活状态(STARTEDRESUMED)才会通知观察者有数据更新

    为什么需要LiveData

    从LiveData具有的特点,我们就能联想到它能够解决我们遇到的什么问题。LiveData具有以下优点:

    • 能够保证数据和UI统一
       这个和LiveData采用了观察者模式有关,LiveData是被观察者,当数据有变化时会通知观察者(UI)。

    • 减少内存泄漏
       这是因为LiveData能够感知到组件的生命周期,当组件处于DESTROYED状态时,观察者对象会被清除掉。

    • 当Activity停止时不会引起崩溃
       这是因为组件处于非激活状态时,不会收到LiveData中数据变化的通知。

    • 不需要额外的手动处理来响应生命周期的变化
       这一点同样是因为LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。

    • 组件和数据相关的内容能实时更新
       组件在前台的时候能够实时收到数据改变的通知,这是可以理解的。当组件从后台到前台来时,LiveData能够将最新的数据通知组件,这两点就保证了组件中和数据相关的内容能够实时更新。

    • 针对configuration change时,不需要额外的处理来保存数据
        我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。

    • 资源共享
       通过继承LiveData类,然后将该类定义成单例模式,在该类封装监听一些系统属性变化,然后通知LiveData的观察者,这个在继承LiveData中会看到具体的例子。

    LiveData使用

    在了解LiveData定义和优点后,那它到底怎么应用呢?LiveData有几种使用方式:

    • 使用LiveData对象
    • 继承LiveData类
    使用LiveData对象

    使用LiveData对象主要有以下几个步骤:

    1. 创建保存特定数据类型的LiveData实例;
    2. 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
    3. 更新Livedata对象存储的数据
    创建LiveData实例

    Android文档中建议LiveData配合ViewModel使用更加哦,其实也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离

    var mCurrentName: MutableLiveData<String> = MutableLiveData()
    
    创建Observer对象,添加观察者

    在onCreate()方法中通过LiveData.observe()方法添加观察者,当数据变化时会通过回调方法通知观察者

     mNameViewModel.mCurrentName.observe(this, Observer { name: String? ->
                binding.nameText.text = name ?: ""
            })
    
    更新LiveData中的数据

    在上面我们已经订阅了LiveData数据变化,我们在xml中增加按钮来改变LiveData中的数据。

    binding.nameBtn.addClickAction {
                mNameViewModel.mCurrentName?.value = "liveData"
            }
    

    我们发现按钮点击,LiveData数据变化时,上面的lambda表达式中会收到更新的通知。

    继承LiveData类

    除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享。

    class TestLiveData() : LiveData<String>() {
    
        var mContextWeakReference: WeakReference<Context>? = null
        private constructor(context: Context) : this() {
            this.mContextWeakReference = WeakReference(context)
        }
    
        companion object {
            var shared: TestLiveData? = null
        }
        fun getInstance(context: Context): TestLiveData? {
            if (shared == null) {
                shared = TestLiveData(context)
            }
            return shared
        }
    
        /**
         * 当这个方法被调用时,
         * 表示LiveData的观察者数量从0变为了1,
         * 这时就我们的位置监听来说,就应该注册我们的时间监听了。
         */
        override fun onActive() {
            super.onActive()
            registerReceiver()
        }
    
        /**
         * 这个方法被调用时,
         * 表示LiveData的观察者数量变为了0,
         * 既然没有了观察者,也就没有理由再做监听,此时我们就应该将位置监听移除。
         */
        override fun onInactive() {
            super.onInactive()
            unregisterReceiver()
        }
    
        private fun registerReceiver() {
            val intentFilter = IntentFilter()
            intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
            mContextWeakReference?.get()?.registerReceiver(mReceiver, intentFilter)
        }
    
        private fun unregisterReceiver() {
            mContextWeakReference?.get()?.unregisterReceiver(mReceiver)
        }
    
    
        private val mReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val action = intent.action
                if (WifiManager.RSSI_CHANGED_ACTION == action) {
                    val wifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)
                    val wifiLevel = WifiManager.calculateSignalLevel(
                            wifiRssi, 4)
                    shared?.setValue("wifiRssi = " + wifiRssi + "  wifiLevel = " + wifiLevel)
                }
            }
        }
    }
    

    TestLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播。然后在广播接收器中更新TestLiveData对象。在使用的时候就可以通过TestLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象,订阅Wifi信息强度变化。

    • onActive(),此方法是当处于激活状态的observer个数从0到1时,该方法会被调用。
    • onInactive() ,此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。

    时序图

    LiveData时序图

    LiveData主要涉及到的时序有三个:

    • 在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)。
    • 根据Fragment/Activity生命周期发生变化时,移除观察者或者通知观察者更新数据。
    • 当调用LiveData的setValue()、postValue()方法后,通知观察者更新数据。

    改变LiveData数据

    LiveData提供了两种改变数据的方法:setValue()和postValue()。区别是setValue()要在主线程中调用,而postValue()既可在主线程也可在子线程中调用。我们先看setValue()方法的具体实现:

    @MainThread
        protected void setValue(T value) {
            assertMainThread("setValue");//判断当前线程是否是主线程,不是主线程就抛出异常
            mVersion++;
            mData = value;
            dispatchingValue(null);
        }
    

    再看下postValue()方法的具体实现:

    protected void postValue(T value) {
            boolean postTask;
            synchronized (mDataLock) {
                postTask = mPendingData == NOT_SET;
                mPendingData = value;
            }
            if (!postTask) {
                return;
            }
            // 会在主线程中执行  mPostValueRunnable中的内容。
            ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
        }
    
    private final Runnable mPostValueRunnable = new Runnable() {
            @Override
            public void run() {
                Object newValue;
                synchronized (mDataLock) {
                    newValue = mPendingData;
                    mPendingData = NOT_SET;
                }
                //noinspection unchecked
                // 在主线程中调用setValue()方法
                setValue((T) newValue);
            }
        };
    

    observe与observeForever

    LiveData提供了两种添加观察者的方法:observeForever()、observe()。
    查看源码:
    observeForever

        @MainThread
        public void observeForever(@NonNull Observer<T> observer) {
            AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
            ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
            if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
                throw new IllegalArgumentException("Cannot add the same observer"
                        + " with different lifecycles");
            }
            if (existing != null) {
                return;
            }
            wrapper.activeStateChanged(true);//设置为true,观察者会一直受到数据的变化
        }
    
    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);//notify数据
                }
            }
    

    通过observeForever()添加观察者,观察者会一直受到数据的变化回到,而不是在组件处于STARTED和RESUMED状态下才会收到,因为这是LifecycleOwner对象就不再是组件了,而是ALWAYS_ON;另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知。

    observe

    @MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                // ignore
                return;
            }
            LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
            // mObservers可以理解成一个类似Map的容器,putIfAbsent()方法是判断容器中的observer(key)
            // 是否有已经和wrapper(value)关联,如果已经关联则返回关联值,否则关联并返回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;
            }
            owner.getLifecycle().addObserver(wrapper);//条件LifecycleOwner的生命周期观察者
        }
    

    将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。

    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);//区别observeForever是在DESTROYED时已帮removeObserver,不需手动remove
                    return;
                }
                activeStateChanged(shouldBeActive());//在activity处于STARTED状态时通知监听者
            }
    
            @Override
            boolean isAttachedTo(LifecycleOwner owner) {
                return mOwner == owner;
            }
    
            @Override
            void detachObserver() {
                mOwner.getLifecycle().removeObserver(this);
            }
        }
    

    LiveData的转换

    有时候有这样的需求,需要在LiveData将变化的数据通知给观察者前,改变数据的类型;或者是返回一个不一样的LiveData。

    这里介绍一个类Transformations,它可以帮助完成上面的这些操作。

    • Transformations.map()

    在LiveData数据的改变传递到观察者之前,在数据上应用一个方法:

    var userLiveData: MutableLiveData<UserModel> = MutableLiveData()
    /**
     * 需要在LiveData将变化的数据通知给观察者前,改变数据的类型
     * 直接赋值,source返回为null
     */
    var userNameLiveData: LiveData<String> = Transformations.map<UserModel, String>(userLiveData, { user ->
                user.userName
            })
    
    @MainThread
        public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
                @NonNull final Function<X, Y> func) {
            final MediatorLiveData<Y> result = new MediatorLiveData<>();
            result.addSource(source, new Observer<X>() {
                @Override
                public void onChanged(@Nullable X x) {
                    result.setValue(func.apply(x));//改变时才设置值
                }
            });
            return result;
        }
    
    • Transformations.switchMap()

    与Transformations.map()类似,只不过这里传递个switchMap()的方法必须返回一个LiveData对象。

    @MainThread
        public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
                @NonNull final Function<X, LiveData<Y>> func) {
            final MediatorLiveData<Y> result = new MediatorLiveData<>();
            result.addSource(trigger, new Observer<X>() {
                LiveData<Y> mSource;
    
                @Override
                public void onChanged(@Nullable X x) {
                    LiveData<Y> newLiveData = func.apply(x);
                    if (mSource == newLiveData) {
                        return;
                    }
                    if (mSource != null) {
                        result.removeSource(mSource);
                    }
                    mSource = newLiveData;
                    if (mSource != null) {
                        result.addSource(mSource, new Observer<Y>() {
                            @Override
                            public void onChanged(@Nullable Y y) {
                                result.setValue(y);
                            }
                        });
                    }
                }
            });
            return result;
        }
    

    示例

    var userNameLiveData2: LiveData<String> =  Transformations.switchMap<UserModel,String>(userLiveData, { user ->
        var liveData: MutableLiveData<String> = MutableLiveData()
        liveData.value = user.userName
        liveData
    })
    

    参考:

    相关文章

      网友评论

          本文标题:Android架构组件-LiveData

          本文链接:https://www.haomeiwen.com/subject/fhshpftx.html