Android Architecture Component之:深层次理解LiveData

LiveData是Architecture Components中的重要一员,本篇将带领大家从源码层面深层次理解它的机制。(此篇不是零基础讲解LiveData和ViewModel的使用,建议往下看的小伙伴先熟悉LiveData和ViewModel的基本使用)

  1. 使用:

    首先在build.gradle中引入:

    def livedata_version = '2.3.0-alpha01'
    def lifecycle_version = '2.2.0'
    def coroutines_android_version = '1.3.3'
    
    // LiveData和ViewModel相关
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$livedata_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    
    // 协程相关
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_android_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_android_version"

    LiveData和ViewModel是必须依赖的,而协程相关依赖不是必须的,而我这里主要是用到了协程。

    涉及到的类:

    • MainActivity:
    class MainActivity : AppCompatActivity() {
    
       private val mViewModel: MainViewModel by lazy {
           ViewModelProvider(this, MainViewModelFactory())[MainViewModel::class.java]
       }
    
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(R.layout.activity_main)
    
           btn_second.setOnClickListener { Intent(this, SecondActivity::class.java).run { startActivity(this) } }
    
           mViewModel.periodTextData.observe(this, Observer {
               Log.e(TAG, "updated: $it")
               tvContent.text = it
           })
    
           mViewModel.dataWithInit.observe(this, Observer {
               Log.e(TAG, "init received $it")
           })
    
           mViewModel.dataWithNoVal.observe(this, Observer {
               Log.e(TAG, "data with no val : $it")
           })
    
           mViewModel.count()
       }
    
       companion object {
           private val TAG = MainActivity::class.java.name
       }
    }

    activity.main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       tools:context=".MainActivity">
    
       <TextView
           android:id="@+id/tvContent"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="Hello World!"/>
    
       <Button
           android:id="@+id/btn_second"
           android:layout_width="wrap_content"
           android:text="go second"
           android:layout_height="wrap_content" />
    
    </LinearLayout>

    MainViewModel.kt

    class MainViewModel : ViewModel() {
    
       val periodTextData = MutableLiveData<String>()
       val dataWithInit = MutableLiveData("hello")
       val dataWithNoVal = MutableLiveData<String>()
    
       fun count() {
           viewModelScope.launch {
               repeat(5) {
                   delay(5000)
                   periodTextData.value = "count: $it"
               }
           }
       }
    }
    
    class MainViewModelFactory : ViewModelProvider.Factory {
       override fun <T : ViewModel?> create(modelClass: Class<T>): T {
           return MainViewModel() as T
       }
    }

    SecondActivity

    class SecondActivity : AppCompatActivity() {
    
    }
  2. 额外补充:

    • viewModelScope,这是lifecycle-viewmodel-ktx依赖中提供给开发者用来启动协程的scope
    • 不用着急,这些代码我们一个个来解析。
  3. 我们假设你已经对LiveData有了基本的了解,我们这里直接从源码入手。我们直接从LiveData类的observe()方法的文档注释入手:

    1. Adds the given observer to the observers list within the lifespan of the given owner. The events are dispatched on the main thread. 

    2. If LiveData already has data set, it will be delivered to the observer. The observer will only receive events if the owner is in Lifecycle.State.STARTED or Lifecycle.State.RESUMED state (active).

    3. If the owner moves to the Lifecycle.State.DESTROYED state, the observer will automatically be removed.

    4. When data changes while the owner is not active, it will not receive any updates. If it becomes active again, it will receive the last available data automatically.

    5. LiveData keeps a strong reference to the observer and the owner as long as the given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to the observer & the owner.

    6. If the given owner is already in Lifecycle.State.DESTROYED state, LiveData ignores the call.

    7. If the given owner, observer tuple is already in the list, the call is ignored.

    8. If the observer is already in the list with another owner, LiveData throws an IllegalArgumentException.

    我们这里将整段文档注释分成了8个点,下面我们一一从实例运行和源码分析角度上来验证这里提到的特性:

    1) 第6点:

    2) 第8点:

    • 这里出现的LifecycleBoundObserver,它会将LifecycleOwner(Activity、Fragment以及Service等)以及observer(observe这个方法的第二个参数)封装到一起。
    • mObservers:observer到LifecycleBoundObserver的映射,它的类型是SafeIterableMap。

    3) 第7点:

    4) 第2点。

    在分析源码之前,我们可以借助于前面已经创建好的工程以及项目代码,我们在MainViewModel里定义了两个MutableLiveData:

    class MainViewModel: ViewModel(){
    val dataWithInit = MutableLiveData("hello")
    val dataWithNoVal = MutableLiveData<String>()
    }
    

    再在MainActivity的onCreate方法里:

    mViewModel.dataWithInit.observe(this, Observer {
       Log.e(TAG, "init received $it")
    })
    
    mViewModel.dataWithNoVal.observe(this, Observer {
       Log.e(TAG, "data with no val : $it")
    })

    运行查看日志输出,只有一行输出:

    init received hello

    也就是说,带初始值的MutableLiveData,一旦被observe,立即会把已有的数据发送给Observer;不带初始值的MutableLiveData则不会这样。这也就验证了这里提到的:If LiveData already has data set, it will be delivered to the observer.

    那么为什么会这样呢?我们一起来分析源代码:

    执行流程就会来到LifecycleRegistry的addObserver()方法:

    那么这个mLifeCycleObserver是谁?看ObserverWithState的构造器

    ObserverWithState(LifecycleObserver observer, State initialState) {
       mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
       mState = initialState;
    }

    执行流程又回到LifecycleBoundObserver的onStateChanged():

     

    那么为什么不带初始值的LiveData在刚开始observe的时候,没有onChanged()通知呢:

     

     

     

    不带参数(即不带初始值)的构造器,mVersion = START_VERSION,这样在considerNotify()方法里:

    在这个地方就直接return回去了,不会调用下面的onChanged回调。

    5) 第3点:If the owner moves to the Lifecycle.State.DESTROYED state, the observer will automatically be removed

    要说明这一点,我们需要知道ReportFragment以及ComponentActivity的存在:

         我们重点关注androidx.core.app.ComponentActivity:

 

这里我们会看到熟悉的LifecycleOwner 接口以及LifecycleRegisty实现类。然后我们再来看ComponentActivity的onCreate()方法里:

 会看到ReportFragment的身影,并且会将ReportFragment添加到Activity中。如果你看过RxPermissions的源码,你就会熟悉这样的套路:在Activity中添加一个Fragment,然后通过该Fragment来感知Activity的相应生命周期回调。由于本小点是在讨论Lifecycle.State.DESTROYED state,所以我们来重点关注ReportFragment的onDestory方法:

不管是进到哪个分支条件,最终都会调用LifecycleRegistry.handleLifecycleEvent()方法:

 

这样执行流程又会到了我们之前提到的onStateChanged()方法: 

看,是不是就把对应Observer移除掉了。

    6) 下面我们就来验证第4点文档注释:When data changes while the owner is not active, it will not receive any updates. If it becomes active again, it will receive the last available data automatically

        和分析第5点一样,我们先不翻看源码,我们通过一个实例来验证。这个时候,我们前面创建的项目工程以及相关类就可以起作用了。

       在MainViewModel类中添加方法:

       

class MainViewModel : ViewModel() {

    val periodTextData = MutableLiveData<String>()

     fun count() {
        viewModelScope.launch {
            repeat(5) {
                delay(2000)
                periodTextData.value = "count: $it"
            }
        }
    }
}

       在MainActivity的onCreate方法中:

 override fun onCreate(savedInstanceState: Bundle?) {
    btn_second.setOnClickListener { Intent(this, SecondActivity::class.java).run { startActivity(this) } }
    
    mViewModel.periodTextData.observe(this, Observer {
            Log.e(TAG, "updated: $it")
            tvContent.text = it
        })

    mViewModel.count()

}

      先解析一下viewModelScope.launch{}中的代码吧: 我们通过viewModelScope启动了一个协程,协程中的代码逻辑是每隔2秒,改变 periodTextData这个MutabeLiveData的值,一共5次。接着就是MainActivity中添加的代码:btn_second就是一个Button,它的点击响应逻辑也就仅仅是跳转到SecondActivity;tvContent是一个TextView,它会显示periodTextData的值。将项目运行起来,我们的操作逻辑是这样的:一打开页面,等个5秒或是10秒钟,看看是否会收到periodTextData值更新的通知(可以通过日志),然后点击btn_second按钮,跳转到SecondActivity,由于协程的代码还是在跑着的,也就是说还在持续更新periodTextData的值,我们可以关注这个时候看看是否会收到periodTextData值更新的通知。最后,我们再从SecondActivity返回,看看tvConten的显示。语言描述起来,有点复杂,我为大家准备了一张gif动图:

    

日志输出如下:

也就是说,在我们跳转并停留在SecondActivity 这段时间里,periodTextData的值一直在更新,但是MainActivity中注册Observer没有接收到值更新的通知。但是一旦我们回到MainActivity(使得MainActivity编程RESUME状态),立马会接收到值更新通知。

    通过这个实例,我们已经验证了文档注释中提到的:When data changes while the owner is not active, it will not receive any updates. If it becomes active again, it will receive the last available data automatically。

    那么源码层面是怎么体现出来的呢?

    和上一条分析一样,我们需要查看ReportFragment的代码实现,找到onResume()方法:

    

 

 

 

 

 

 以上这些分析流程,我们在前面多条的分析过程中,都已经走过逻辑。最终回到considerNotify()方法:

而在LiveData的setValue()方法里:

 每调用一次setValue方法,mVersion的值都会加1。那么considerNotify()中的observer.mLastVersion >= mVersion的判断条件就不会满足,自然也就会走到下面的onChanged()方法里,从而触发我们的Observer中的逻辑。可见,这个LiveData的mVersion是至关重要的,顾名思义,它就是记录LiveData中value值的版本。

至此,整篇文章对于LiveData的源码分析就结束了。文章中存在大量的截图,感谢您的阅读!

关于ViewModel的深层次源码分析可以参考此篇

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值