Android开发——架构组件LiveData源码解析

近期的业务代码中使用到了LiveData,
研究了一下发现很好用,因此总结整理出了此篇学习笔记。希望各位多批评指正。

1. LiveData概述

简单地来说,LiveData就是一个持有数据的类。

  • LiveData中的数据可以被观察者订阅,当数据被修改时通知观察者。观察者包括Fragment、Activity以及Service等。
  • LiveData能够感知观察者的生命周期。只有在观察者处于激活状态(STARTED、RESUMED)才会收到数据更新;并在未激活时自动解注册观察者,避免崩溃,且减少内存泄露。
  • 当我们采用LiveData保存数据时,数据和组件的分离使得组件在ReCreate时保证数据不丢失。
需要注意的是:
(1)当观察者从后台到前台来时,LiveData能够将最新的数据通知给观察者,保证数据实时更新;
(2)组件在ReCreate时,会经历N个生命周期方法,但是ViewModel还是之前的对象。因此LiveData常结合VM使用。

2. LiveData的使用

LiveData的使用有两种方式,结合ViewModel使用LiveData对象或者直接继承LiveData类。

2.1 结合ViewModel使用LiveData对象

以一个简单的例子展示,使用LiveData子类MutableLiveData,维护一个String类型的数据:

public class MyViewModel extends ViewModel{

    // Create a LiveData with a String
    private MutableLiveData<String> mData;

    public MutableLiveData<String> getCurrentData() {
        if (mData == null) {
            mData = new MutableLiveData<>();
        }
        return mData;
    }
}

接着,创建并注册观察者:

public class LiveDataFragment extends Fragment{

    private MyViewModel mViewModel;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //这里执行注册
        mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
        mViewModel.getCurrentData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String data) {
                //LiveData数据变化后的回调
            }
        });
    }

}

使用setValue更新LiveData中的数据

mViewModel.getCurrentData().setValue("yanxuan");

2.2 直接继承LiveData类

除了直接使用LiveData对象,还可以通过直接继承LiveData类来定义适合特定需求的LiveData。下面的例子使用LiveData简单地实现一个资源共享的需求。

public class MyLiveData extends LiveData<Integer> {
    private static MyLiveData mData;
    private WeakReference<Context> mContext;

    public static MyLiveData getInstance(Context context){
        if (mData == null){
            mData = new MyLiveData(context);
        }
        return mData;
    }

    private MyLiveData(Context context){
        mContext = new WeakReference<>(context);
    }

    @Override
    protected void onActive() {
        super.onActive();
        registerReceiver();
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        unregisterReceiver();
    }

    private void registerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        mContext.get().registerReceiver(mReceiver, intentFilter);
    }

    private void unregisterReceiver() {
        mContext.get().unregisterReceiver(mReceiver);
    }


    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mData.setValue(getWifiLevel(intent));
        }
    };
}

在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播,并且在广播接收器中更新数据。 在使用的时候就可以通过MyLiveData.getInstance().observe()方法来添加观察者对象和observer。

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

3. LiveData源码解析

主要从以下三个方面进行分析:

  • 在Fragment/Activity中通过LiveData.observe()注册观察者
  • 根据Fragment/Activity生命周期的变化,实时移除观察者;或者从后台转到前台时通知观察者更新数据
  • 当调用LiveData的setValue()或postValue()方法后,通知观察者更新数据

3.1 注册观察者

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象
    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对象和Observer对象封装成LifecycleBoundObserver对象,LifecycleBoundObserver是一个内部类,它继承自ObserverWrapper,并实现了GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。当组件生命周期变化时会通过onStateChanged()方法回调过来。

3.2 感知生命周期变化

通过上面的分析,观察者就是LifecycleBoundObserver对象,下面我们看一下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) {
            //DESTROYED状态下移除观察者
            //该行代码会间接调用下面的detachObserver()方法
            removeObserver(mObserver);
            return;
        }
        //判断是否处于actived状态,并将结果作为参数传递给activeStateChanged()
            activeStateChanged(shouldBeActive());
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

当组件(Fragment/Activity)生命周期发生变化时,onStateChanged()方法会被调用。如果当前处于Lifecycle.State.DESTROYED时,会自动将观察者移除;若当前处于ACTIVE状态,则继续调用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); //数据通知
    }
}

可以看到,若新状态和之前状态相同,则不进行不处理。 并且,当处于激活状态的observer个数从0到1时,调用onActive(); 当处于激活状态的observer个数从1到0时,调用onInactive()。

以上的onActive()和onInactive()都是空实现的方法,继承类可以选择去实现

最后调用的是dispatchingValue()进行数据变化时的消息通知,最终的回调代码如下。mObserver即为调用observe()注册时传入的Observer对象。

observer.mObserver.onChanged((T) mData);

3.3 改变数据后的通知逻辑

LiveData提供了两种改变数据的方法:在主线程调用的setValue()方法,以及在子线程中调用的postValue()方法。我们先看setValue()方法的具体实现:

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

首先判断当前线程是否是主线程,不是就会抛出异常。将数据赋值给mData后,调用了dispatchingValue()进行数据通知,该方法3.2中已经讨论过了。

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        //数据赋值给mPendingData,等待在主线程中使用
        mPendingData = value;
    }
    if (!postTask) {return;}
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

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

在postValue()方法中,通过ArchTaskExecutor实现在主线程中执行mPostValueRunnable中的内容,而在mPostValueRunnable的run()中最终会调用setValue()方法来实现改变LiveData中的数据。

4. 总结

结合ViewModel的生命周期特点,LiveData很适合用于Fragment与Fragment之间的通信、Fragment与Activity之间的通信等。

需要注意的是,数据发送方和接收方传给方法ViewModelProviders.of()的对象必须一致,
最终得到的才是同一个ViewModel对象。
转载请注明出处:https://blog.csdn.net/SEU_Calvin/article/details/82256693

5. 踩坑

1. 当Fragment被detach再attach回来之后,如果你每次在onCreateView都会add新的observer实例,会导致添加多个observer。

这是因为Fragment在onDestroy才通知LiveData移除observers,若每次onCreateView都会add新的observer实例,这样就会导致数据更新时,LiveData会同时通知多个Observer,界面就会快速刷新多次。解决方式是当你在onCreateView方法中添加LiveData.observer(LifecycleOwner owner, Observer<T> observer)时,第一个参数使用Fragment.getViewLifecycleOwner()方法返回值。

2. 如果你使用了Fragment.getViewLifecycleOwner()作为参数, 但是同时自己又在onCreateView中处理了Fragmeng缓存, 导致不管如何切换fragment, 仅第一次才去add observer实例,这样的写法显然会导致attach回来之后observer失效。解决方法之一是改回Frament作为参数,或者每次onCreateView都保证去add一次observer实例。 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Jetpack是Google提供的一套用于加速Android应用开发的工具包,其中包括了许多架构组件,其中之一就是ViewModelViewModel是一种设计模式,用于保存和管理与UI相关的数据。在传统的Android开发中,当屏幕旋转或者因为其他原因导致Activity或Fragment重建时,之前保存的临时数据就会丢失。而ViewModel的出现解决了这个问题。 ViewModel的主要作用是将数据与UI组件分离。它的工作方式是创建一个ViewModel类,并在其中保存需要与UI组件交互的数据。这样,当屏幕旋转或重建时,ViewModel实例不会销毁,数据也会得到保留。然后,在Activity或Fragment中,通过获取ViewModel实例,可以轻松地访问这些数据。 使用ViewModel的好处有很多。首先,它可以避免内存泄漏,因为ViewModel的生命周期与Activity或Fragment无关。其次,它可以节省资源,因为当Activity或Fragment销毁时,ViewModel实例可以被系统缓存起来,下次再创建时可以直接返回该实例。另外,由于ViewModel保存了与UI相关的数据,可以减少因为屏幕旋转导致的数据重复加载的问题。 在使用ViewModel时,你可以选择使用Android Jetpack中的其他架构组件来进一步提高开发效率,比如通过LiveData实现数据的观察和通知,或者通过DataBinding来实现UI与数据的自动绑定。 总之,ViewModelAndroid Jetpack中非常重要的一个架构组件,它的出现实现了数据与UI的解耦,提高了开发效率,并且解决了数据丢失的问题。希望通过这篇文档的详解,你对ViewModel有了更深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值