会议室数据库查询后未触发实时数据观察器

时间:2019-01-18 20:14:10

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

我有一个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
}

ViewModel:

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()
    }
}
}

房间db:

@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"))
    }
}
}

1 个答案:

答案 0 :(得分:0)

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

我没有意识到的是,这基本上与LiveData的设计背道而驰。 LiveData是您订阅的数据,订阅该数据的客户端不影响它,它仅侦听其更改。 所以这里的问题是设计。

要获取新查询,您通常需要新数据(以便观察会触发)或重新订阅LiveData-一种更困难,更复杂的方法,因为这时您需要管理订阅,因此您无需泄漏。 一旦选择了意图,我便选择通过插入来获取新数据。如果有人愿意,我可以为此发布固定代码。