【问题标题】:Live data observer not triggered after room db query房间数据库查询后未触发实时数据观察器
【发布时间】:2019-01-18 20:14:09
【问题描述】:

我有一个 LiveData 对象,我在活动的片段中观察它。该活动通过 2 个广播接收器侦听来自系统的广播。根据当前日期从房间查询数据。因此接收器检测日期是否已更改,如果已更改,则继续刷新查询。

问题是在我更改设置中的日期并返回应用程序后,没有触发观察者。如果我去另一个片段并返回数据会改变,但不是来自

现在是代码:

活动:

     private lateinit var timeReceiver: MyTimeReceiver

     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        timeReceiver = MyTimeReceiver()
        registerReceiver(timeReceiver, filter)
        registerReceiver(refreshReceiver, IntentFilter("refresh_data"))
        mainFragment = MainFragment.newInstance()

       }

 private val refreshReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == "refresh_data") {
                Timber.e("time changed, need to refresh data")                         
                mainFragment.refreshData()
            }
        }
    }

 override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeReceiver)
        unregisterReceiver(refreshReceiver)
    }

片段:

private var counter: Int = 0
private lateinit var viewModel: MainFragmentViewModel
private lateinit var date: String

companion object {
    fun newInstance(): MainFragment {
        return MainFragment()
    }
}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_main, container, false)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    plus_btn.setOnClickListener { addCup() }
    minus_btn.setOnClickListener { decreaseCup() }
    viewModel = ViewModelProviders.of(this).get(MainFragmentViewModel::class.java)
    viewModel.dataList.observe(viewLifecycleOwner, Observer {
            it.let { it1 ->
                counter = it1.size
                cup_counter.text = "$counter"
                setGoalVisibility()
            }
    })
}

override fun onResume() {
    super.onResume()
    viewModel.checkCups(setDate())
}

private fun decreaseCup() {
    viewModel.deleteCup(counter, date)
}

private fun addCup() {
    Timber.e(date)
    viewModel.insertCup(
        WaterCupEntity(
            System.currentTimeMillis(),
            ++counter,
            date
        )
    )
}
fun refreshData() {
    viewModel.checkCups(setDate())
}

private fun setDate(): String {
    val dateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.US)
    date = dateFormat.format(Calendar.getInstance().time)
    return date
}

视图模型:

class MainFragmentViewModel(application: Application) : AndroidViewModel(application) {

private var dao: WaterCupDao
var dataList: LiveData<List<WaterCupEntity>>
private var job = Job()
private val coroutineContext: CoroutineContext
    get() = job + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
private val dateFormat: SimpleDateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.US)
var date: String

init {
    dao = MyCupsDb.getInstance(application, scope).getDao()
    date = dateFormat.format(Calendar.getInstance().time)
    Timber.e("getting all cups for date: %s", date)
    dataList = dao.getAllCupsWithSameDate(date)
}

fun checkCups(date :String) {
    dataList = dao.getAllCupsWithSameDate(date)
}

fun insertCup(cup: WaterCupEntity) = runBlocking {
    scope.launch(Dispatchers.IO) {
        dao.insert(cup)
    }
}

fun deleteCup(number: Int, date: String) =
    scope.launch(Dispatchers.IO) {
        dao.deleteCupForDate(number, date)
    }

fun deleteToday(date :String) {
    scope.launch (Dispatchers.IO){
        dao.deleteAllCupsForDate(date)
    }
}

fun deleteAllCups() {
    scope.launch (Dispatchers.IO){
        dao.deleteAllCups()
    }
}
}

房间数据库:

@Database(entities = [WaterCupEntity::class], version = 1)
abstract class MyCupsDb : RoomDatabase() {
abstract fun getDao(): WaterCupDao

companion object {

    @Volatile
    private var instance: MyCupsDb? = null


    fun getInstance(context: Context, scope:CoroutineScope): MyCupsDb {
        return instance ?: synchronized(this) {
            instance ?: buildDb(context,scope).also { instance = it }
        }
    }

    private fun buildDb(context: Context,scope:CoroutineScope): MyCupsDb {
        return Room.databaseBuilder(context, MyCupsDb::class.java, "myDb")
            .addCallback(WordDatabaseCallback(scope))
            .build()
    }
}

private class WordDatabaseCallback(
    private val scope: CoroutineScope

) : RoomDatabase.Callback() {

    override fun onCreate(db: SupportSQLiteDatabase) {
        super.onOpen(db)
        instance?.let { database ->
            scope.launch(Dispatchers.IO) {
                populateDatabase(database.getDao())
            }
        }
    }

    fun populateDatabase(dao: WaterCupDao) {
        var word = WaterCupEntity(System.currentTimeMillis(),1,"11.01.2019")
        dao.insert(word)
        word = WaterCupEntity(System.currentTimeMillis(),2,"11.01.2019")
        dao.insert(word)
    }
}
}

MyTimeReceiver:

class MyTimeReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
    when (intent.action){
        Intent.ACTION_TIMEZONE_CHANGED,
        Intent.ACTION_DATE_CHANGED,
        Intent.ACTION_TIME_CHANGED,
        Intent.ACTION_TIME_TICK -> context.sendBroadcast(Intent("refresh_data"))
    }
}
}

【问题讨论】:

    标签: android android-room android-architecture-components android-broadcastreceiver android-livedata


    【解决方案1】:

    所以主要的用例是在某个事件之后触发LiveData 查询——在这种情况下是来自BroadcastReceiver 的意图——所以它被刷新了。 我想为查询添加新参数,然后使查询工作。

    我没有意识到这基本上违背了LiveData的设计。 LiveData 是您订阅的数据,订阅该数据的客户端不会影响它,它只会监听它的变化。 所以这里的问题在于设计。

    要获得新查询,您通常需要新数据(因此您的观察将触发)或重新订阅LiveData - 从那时起,您需要管理订阅以防止泄漏,这是一种更难、更复杂的方法. 一旦我得到一个意图,我选择通过使用插入来获取新数据。如果有人愿意,我可以为此发布固定代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多