Android 全面深入剖析JetPack之LiveData源码

1,144 阅读6分钟

LiveData介绍

LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或Service 等组件的生命周期。在底层数据更改时通知视图,言外之意就是数据一经更改,就去通知视图去更新数据。

LiveData优点

  1. 实时数据刷新,实时更新UI
  2. 避免出现内存泄漏问题
  3. 避免了由Activity处于stop状态而引起的崩溃
  4. 屏幕发生旋转或回收时也能立即取到数据
  5. 避免了界面由生命周期而出现的问题

LiveData使用步骤

  • 在ViewModel中创建一个持有某种数据类型的LiveData ,通常是用子类MutableLiveData定义
  • 通过 observe 方法可以订阅修改数据的通知
  • 通过 postValue()或者 setValue() 方法发送事件更新数据
  • 已经订阅的 Observer 就能够得到数据更改时的通知并回调 onChanged() 方法
  • 在onChanged()方法中更新数据更新UI

LiveData简单使用

        //观察者角色
  	myViewModel.getData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String data) {
                mainBinding.textView.setText(data);
            }
        });
        
        //被观察者角色
        mainBinding.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.getData().setValue("狗哥很帅`!");`
            }
        });

源码分析

LiveData中的observe()源码解析

先看看LiveData中observe()方法的参数

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
  
    }

思考

我们看到LiveData源码中observe()方法第一个参数是 LifecycleOwner,而我们代码中传递的是当前页面上下文this,为什么不会报错 ?this 和 LifecycleOwner 有何关系呢 ?

分析

我们看当前 MainActivity继承自 AppCompatActivity

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

再看看AppCompatActivity,

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
}

发现AppCompatActivity又继承自FragmentActivity,在继续看看FragmentActivity是什么东西:

public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {

又发现FragmentActivity继承自ComponentActivity,这时候哥哥们可能会有些不耐烦了,稳住稳住,马上就到了:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {}
}

这时候大家发现了,MainActivity 的终极父类其实是实现了 LifecycleOwner 的接口,所以传递this不会报错。而observe()的第一个参数其实就相当于一个被观察者,第二个参数observer就相当于观察者。

分析完observe()的构造方法,接下来我们看看observe()方法做了哪些操作:

@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);
    }
1. assertMainThread("observe");
assertMainThread("observe");
 static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
 }

我们可以查看他的源码发现: 这个个方法中判断了当前线程是否为主线程,如果不是主线程则抛出异常

2. if()判断生命周期状态
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    return;
}

通过owner获取到当前页面的生命周期状态是否被销毁,如果销毁则return,可以避免内存泄漏的情况

3. LifecycleBoundObserver装饰器
 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

相当于一个装饰器,将持有者(被观察者Activity)和观察者都装进去

LifecycleBoundObserver源码

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //如果前页面的生命周期状态是否被销毁,如果销毁则removeObserver(mObserver),即移除Observer;
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
4. ObserverWrapper缓存
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

mObservers源码

 private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

mObservers是一个Map,相当于缓存,缓存一份装饰器,key为observer,value为装饰器wrapper

总结

整个LiveData都是时刻去观察生命周期的状态,从而从根源上避免了内存泄漏的出现,这也是目前好多公司采用jetpack的原因

LiveData中setValue()源码解析

这里我还是重复放一下使用的那段代码吧,也便于大佬们更好的分析,大佬们莫怪!

       //观察者角色
       myViewModel.getData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String data) {
                mainBinding.textView.setText(data);
            }
        });
        
        //被观察者角色
        mainBinding.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myViewModel.getData().setValue("哈哈哈哈");
            }
        });

思考

观察者是如何监听到被观察者的数据实时变化呢?

分析

我们来看被观察者的触发过程:

 myViewModel.getData().setValue("哈哈哈哈");

这里发现其实是通过setValue()方法进行触发的,那我们进去看看这个setValue()方法:

@SuppressWarnings("WeakerAccess")
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);
    }
}

通过super.setValue(value),调用父类的setValue(),将 value 传入,即 LiveData 的setValue(value)方法。 我们继续看看 super.setValue(value)方法:

 @MainThread
    protected void setValue(T value) {
    	//这里又一次判断了是否为主线程,如果不是主线程,则抛出异常
        assertMainThread("setValue");
        mVersion++;
        //将value赋值给data
        mData = value;
        //分发value,
        dispatchingValue(null);
    }

mVersion

LiveData内维护的mVersion表示的是发送信息的版本,每次发送一次信息, 它都会+1, 而ObserverWrapper内维护的mLastVersion为订阅触发的版本号, 当订阅动作生效的时候, 它的版本号会和发送信息的版本号同步.他们初始值都为-1。

思考

dispatchingValue(null) 参数传递 null 有何意义呢 ?

分析

我们继续查看dispatchingValue()的源码

 @SuppressWarnings("WeakerAccess") /* synthetic access */
    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;
    }

这里我们主要分析这段代码:

 for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }

当我们有多个被观察者时,遍历所有的观察者并取出观察者:即:

new Observer<String>() {
            @Override
            public void onChanged(String data) {
                mainBinding.textView.setText(data);
            }
        }

然后通过considerNotify唤醒

considerNotify()
 @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
if (!observer.mActive) {
    return;
}

这个判断什么意思呢?

如果 observer.mActive ==true , 则我们的当前页面时可见状态,即处于 onResume() 状态,而这里是 !observer.mActive,即当前页面处于不可见的状态,而后 return ;

这样做的好处是又一次的去避免了内存的泄漏;

举个例子

举个栗子:假如我们刚启动Activity,然后迅速的关闭掉Activity,这时候刚打开这个Activity的时候已经发起了网络请求,进而要去请求数据并通知界面去刷新UI,这时候就会走considerNotify方法去通知控件,而当页面关闭的话,是找不到控件的,这时候就会引发崩溃问题,所以这里这个判断又一次的判断了当前页面是否处于可见状态,如果为可见状态则去onChanged数据,如果不可见则直接return,也从而避免了崩溃和内存泄漏的问题!

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

mData即为改变的数据,通过mObserver调用onChange(mData),这时候数据 data 就回到了 onChanged()方法中了。

//观察者角色
myViewModel.getData().observe(this, new Observer<String>() {
    @Override
    public void onChanged(String data) {
       //数据就回到了这里的onChanged方法
       mainBinding.textView.setText(data);
    }
});

总结

  1. LiveData 内部实现了观察者模式,如果数据要同时通知几个界面,可以采取这种方式
  2. LiveData 数据变化的时候,会回调 Observer 的 onChange 方法,但是回调的前提是 lifecycleOwner(即所依附的 Activity 或者 Fragment) 处于 onStart() 或者 onResume() 状态,它才会回调,否则,必须等到 lifecycleOwner 切换到前台的时候,才回调,其内部解决了因为Lifecycle而导致的崩溃,内存泄漏等问题。因此,这对性能方面确实是一个不小的提升。

传送门

这是我写的一个基于ViewModel + LiveData+ DataBinding、多语言化、矢量图、约束性布局的篮球计分器的一个学习的简单Demo

github.com/SmartTwoDog…