WeakReference函数类型参数null行为

时间:2018-02-10 22:42:49

标签: android kotlin weak-references android-livedata android-viewmodel

据我所知,WeakReference将允许垃圾收集器清除其引用,如果不再需要它作为强引用(例如正在销毁的Activity或正在清理的ViewModel)。但我试图理解这样一种情况:当函数的拥有实例没有被垃圾收集时,我的函数WeakReference在随机点返回一个空引用...

考虑以下ViewModel:

class SampleVM(dao: MyRoomDao) : ViewModel() {
    private val mLiveData: LiveData<List<Object>> = dao.loadAll()
    private val mMediatorLiveData: MediatorLiveData<List<Object>> = MediatorLiveData()

    init {
        mMediatorLiveData.addSource(mLiveData, { dbResult ->
            MyAsyncTask(
               mMediatorLiveData::setValue
        ).execute(dbResult ?: ArrayList())
    })

    ...
}

我将原始LiveData的结果传递给AsyncTask,并将function type reference传递给setValue,以便AsyncTask可以在onPostExecute()中调用介体的setValue()。

考虑以下AsyncTask:

class MyAsyncTask(onFinishCallback: (List<Object>) -> Unit) : AsyncTask<...,...,...>() {
   private val mOnFinishCallback = WeakReference<(List<Object>) -> Unit>(onFinishCallback)

   ...(overrides)...

   override fun onPostExecute(result: List<Object>?) {
      result?.let {
         mOnFinishCallback.get()?.invoke(it)
   }

我认为只要onCleared()没有在ViewModel上调用,并且它没有被垃圾收集,WeakReference将始终包含非空引用。但碰巧有两种情况我已经看到mOnFinishCallback.get()返回null。

  1. 在应用程序运行时,按“运行”(Shift + F10),通过Android Studio重新启动应用程序。该应用程序将关闭,重新启动,我之前有物品的RecyclerView现在是空白的。通过一些sysout,我可以看到WeakReference有一个空引用。
  2. 通过FAB(通过DAO实例处理插入)向列表中添加新项目并观察我的日志时,WeakReference大多数时候仍然引用我的MediatorLiveData的setValue()函数,但是随机次,它将为null,但是下次我插入一个项目并重复此过程时,它不是空的。
  3. 知道为什么会这样吗?如果我的ViewModel和MediatorLiveData仍然处于活动状态并且没有被垃圾收集,那么MediatorLiveData的setValue()函数引用是否应该在整个时间内都有效?

1 个答案:

答案 0 :(得分:0)

当您的方法MediatorLiveData::addSource返回时,没有强烈的引用您的功能界面(您想要调用mMediatorLiveData::setValue),这意味着它适用于GC。

从不存在对函数本身的实例变量引用,它只是一个方法参数。

您应该持有对功能界面本身的引用,只要您需要它,因此它可以调用setValue