Android LiveData存在值但赋值给变量后为null问题求助
问题解决:LiveData赋值后变量仍为null的原因及修复方案
这不是线程问题,核心原因是LiveData的异步回调特性:你的代码执行顺序是同步流程,但Room的查询是异步操作,observe里的回调只会在查询完成后才触发。具体执行步骤:
- 先初始化
loginCredentials为null - 注册LiveData的观察者,但此时Room还在后台处理查询,回调未执行
- 立刻执行
Log.e("Login variable", loginCredentials.toString())——这时候变量自然还是null - 等Room查询完成,回调才会触发,给
loginCredentials赋值并打印Login it的日志
下面是几种可行的修复方案:
方案一:把业务逻辑移到回调内部(最直接)
只有在observe的回调里,才能确保数据已经加载完成,所有需要用到loginCredentials的逻辑都应该放在这里:DBUtils.with(this).getDB().userDao() .loginValidation(accoutNo, pincode) .observe(this) { user -> // 在这里处理登录相关逻辑,比如跳转页面、提示错误等 Log.e("Login user", user.toString()) if (user != null) { // 登录成功,跳转到主页 startActivity(Intent(this, MainActivity::class.java)) finish() } else { Toast.makeText(this, "账号或密码错误", Toast.LENGTH_SHORT).show() } }方案二:用协程+Flow替代LiveData(推荐,更灵活)
如果项目已经引入协程,可以把Dao的返回类型改成Flow,这样能更灵活地处理异步数据:- 先修改Dao层代码:
@Query("SELECT * FROM user WHERE account_no = :accoutNo AND pincode = :pincode") fun loginValidation(accoutNo: String, pincode: String): Flow<User?> - 在Activity中用协程收集数据:
lifecycleScope.launch { DBUtils.with(this@YourActivity).getDB().userDao() .loginValidation(accoutNo, pincode) .collect { user -> loginCredentials = user Log.e("Login variable", loginCredentials.toString()) // 在这里处理后续业务逻辑 } }
- 先修改Dao层代码:
方案三:慎用LiveData的getValue()(不推荐)
getValue()只能在主线程调用,而且只有当LiveData已经持有数据时才会返回有效值,如果查询还没完成,调用它依然会得到null,所以只适合确定数据已加载的场景:val userLiveData = DBUtils.with(this).getDB().userDao().loginValidation(accoutNo, pincode) userLiveData.observe(this) { loginCredentials = it } // 仅作演示,实际大概率还是null,不建议这么用 val tempUser = userLiveData.value Log.e("Login variable", tempUser.toString())
内容的提问来源于stack exchange,提问作者Malhar
相关产品推荐
相关产品推荐

