【问题标题】:WeakReference to function type parameter null behavior对函数类型参数空行为的弱引用
【发布时间】:2018-07-21 10:26:53
【问题描述】:

我了解,如果不再需要将 WeakReference 作为强引用(例如销毁 Activity 或清理 ViewModel),WeakReference 将允许垃圾收集器清理其引用。但是我试图理解这样一种情况,即当函数拥有的实例尚未被垃圾收集时,我对函数的 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)
   }

我认为只要未在 ViewModel 上调用 onCleared() 并且未对它进行垃圾回收,WeakReference 将始终包含非空引用。但碰巧我见过两种情况 mOnFinishCallback.get() 返回 null。

  1. 在应用程序运行时,通过 Android Studio 按运行 (Shift + F10) 重新启动应用程序。该应用程序将关闭,重新启动,并且我之前有项目的 RecyclerView 现在是空白的。通过一些系统输出,我可以看到 WeakReference 有一个空引用。
  2. 在通过 FAB 向列表添加新项目(通过 DAO 实例处理插入)并查看我的日志时,大部分时间 WeakReference 仍在引用我的 MediatorLiveData 的 setValue() 函数,但它会在随机时间null,但下次我插入一个项目并重复此过程时,它不为 null。

知道为什么会这样吗?如果我的 ViewModel 以及 MediatorLiveData 仍然处于活动状态并且没有被垃圾收集,那么 MediatorLiveData 的 setValue() 函数引用是否应该一直有效?

【问题讨论】:

  • 当然,一旦.addSource 方法返回,那么就没有对你的功能接口(你想在其中调用mMediatorLiveData::setValue)的强引用,这意味着它是由 GC 决定的——从来没有实例变量引用函数本身,它只是一个方法参数。 ?
  • 也可能是功能界面上inlinenoinline的区别。
  • 就是这样。在 ViewModel 中,我创建了如下引用: private val mCallback = mMediatorLiveData::setValue 并将其传递给 AsyncTask 的构造函数。随意写一个答案,我会将其标记为已接受。
  • 很高兴解决了!

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


【解决方案1】:

当您的方法 MediatorLiveData::addSource 返回时,没有强引用您的功能接口(您要在其中调用 mMediatorLiveData::setValue),这意味着它可以用于 GC。

函数本身从来没有实例变量引用,它只是一个方法参数。

您应该持有对功能接口本身的引用,只要您需要它,它就可以调用setValue

【讨论】:

    猜你喜欢
    • 2017-09-23
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    相关资源
    最近更新 更多