Наблюдатель данных в реальном времени не запускается после запроса комнатной базы данных - PullRequest
0 голосов
/ 18 января 2019

У меня есть объект 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()
    }
}
}

Номер базы данных:

@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 голосов
/ 26 января 2019

Таким образом, в основном сценарий использования состоял в том, чтобы инициировать запрос LiveData после некоторого события - в данном случае намерения из BroadcastReceiver - так что он обновляется. Я хотел поставить новые параметры для запроса, а затем заставить запрос работать.

Что я не понял, так это то, что это в основном против дизайна LiveData. LiveData - это данные, на которые вы подписываетесь, клиент, который подписывается на эти данные, не влияет на них, он просто слушает их изменения. Так что проблема здесь с дизайном.

Чтобы получить новый запрос, вам обычно нужны либо новые данные (чтобы ваши наблюдения сработали), либо повторная подписка на LiveData - более сложный и сложный подход, так как тогда вам нужно управлять подписками, чтобы не допустить утечки , Я решил получить новые данные с помощью вставки, как только я получу намерение. Если кто-то пожелает, я могу опубликовать фиксированный код для этого.

...