【问题标题】:Livedata returned by Room won't be triggered after GCRoom 返回的 Livedata GC 后不会触发
【发布时间】:2018-09-11 09:30:43
【问题描述】:

我们的团队正在构建一个受益于 Android Jetpack 的项目。

有演示代码显示了我们面临的问题。这些代码可以在https://github.com/viseator/TestRoomLivedata找到

我创建了一个UserDao

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE uid = :uid LIMIT 1")
    fun findUserById(uid: String?): Single<User>

    @Query("SELECT * FROM user WHERE state = 1 LIMIT 1")
    fun findLoginUserWithObserve(): LiveData<User>

    @Query("SELECT * FROM user WHERE state =1 LIMIT 1")
    fun findLoginUser(): Single<User>

    @Update
    fun update(vararg user: User)
}

我还创建了一个 kotlin 对象来管理用户的状态。

我正在观察findLoginUserWithObserve() 返回的实时数据,以便在登录用户更改时得到通知:

object AccountManager {
    private const val DATA_BASE_NAME = "users"
    val TAG = "AccountManager"
    fun init(context: Application) {
        sDb = databaseBuilder(context, UserDataBase::class.java, DATA_BASE_NAME).build()
        sDao = sDb.userDao()
        sDao.findLoginUserWithObserve().observeForever {
            Log.d(TAG, "notified: $it")
        }
    }

    private lateinit var sDb: UserDataBase
    private lateinit var sDao: UserDao

    fun findLoginUserWithObserve() = sDao.findLoginUserWithObserve()

    fun logoutFlowable(): Single<Boolean> = sDao.findLoginUser().subscribeOn(
            Schedulers.io()).map { user ->
        user.state = User.STATE_NOT_LOGIN
        sDao.update(user)
        true
    }

    fun login(user: User) = logoutFlowable().subscribe({ doLogin(user) }, { doLogin(user) })

    private fun doLogin(user: User) = sDao.findUserById(user.uid).subscribeOn(
            Schedulers.io()).subscribe({ origin ->
        origin.userName = user.userName
        origin.state = User.STATE_HAVE_LOGIN
        sDao.update(origin)
        user.state = User.STATE_HAVE_LOGIN
    }, {
        user.state = User.STATE_HAVE_LOGIN
        sDao.insert(user)
    })

}

我通过调用init 方法在Applicaiton 中初始化AccountManager 并创建一个演示活动:

class MainActivity : AppCompatActivity() {
    private var i = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        AccountManager.login(User().apply {
            userName = "user1"
            uid = System.currentTimeMillis().toString()
        })
        button.setOnClickListener {
            AccountManager.login(User().apply {
                userName = "user${i++}"
                uid = System.currentTimeMillis().toString()
            })
        }
    }
}

我想一旦AccountManager.login() 被调用,我会收到通知并打印一条日志消息。但是我们发现GC之后我们就不会再收到通知了。 (我们通过 Android Studio Profiler 触发 GC)

Log message

在探索了room生成的UserDao_Impl类之后,我们发现它通过调用addWeakObserver()创建了一个观察者并链接到数据库:

  @Override
  public LiveData<User> findLoginUserWithObserve() {
    final String _sql = "SELECT * FROM user WHERE state = 1 LIMIT 1";
    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
    return new ComputableLiveData<User>(__db.getQueryExecutor()) {
      private Observer _observer;

      @Override
      protected User compute() {
        if (_observer == null) {
          _observer = new Observer("user") {
            @Override
            public void onInvalidated(@NonNull Set<String> tables) {
              invalidate();
            }
          };
          __db.getInvalidationTracker().addWeakObserver(_observer);
        }

所以我们想知道为什么房间在这里使用WeakObserver,这使得房间返回的实时数据不可靠?

PS:我们正在使用FlowableonNext() 中发出实时数据来解决这个问题,onNext() 将按预期每次触发。

【问题讨论】:

    标签: android android-room android-architecture-components android-jetpack


    【解决方案1】:

    将此问题发布到谷歌问题跟踪器(https://issuetracker.google.com/issues/114833188)后,我得到了回复:

    如果不再使用 LiveData,我们不想泄露它。我们可以 从技术上讲,当 LiveData 存在时,继续添加和删除观察者 使用/未使用;但这可能意味着错过一些发生的事件 当 LiveData 处于非活动状态时。我们最初是这样做的 原型,但变得更难维护。你应该保留一个参考 到 LiveData 以继续使用它。这是我们在所有使用的模式 例子。

    所以只需保留对 room 返回的 livedata 的引用,而不是仅仅观察它,现在一切正常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      相关资源
      最近更新 更多