Saya memiliki aplikasi sederhana yang menampilkan daftar kontak yang diambil dari API.
Saya perlu menampilkan pengambilan kontak terbaru jika tidak ada jaringan saat peluncuran aplikasi. Jadi itulah mengapa saya bekerja dengan Room untuk menyimpan kontak ke dalam database.

Kontak disimpan dengan benar, ditarik dengan benar saat dibutuhkan.
Tapi ada masalah aneh ketika saya melakukan pola berikut:
- Saya menarik beberapa kontak dari API (disimpan otomatis ke db lokal)
- Saya mematikan aplikasi;
- Saya memotong semua jaringan untuk memicu penarikan dari db lokal;
- Saya meluncurkan aplikasi tanpa jaringan apa pun, kontak ditampilkan dengan benar dari db lokal;
- Saya membuka jaringan untuk memproses panggilan baru ke API (bersihkan db dan seterusnya...)
- Setelah menanggapi panggilan ke API, setelah berlangganan panggilan getContacts, berlangganan getContactsFromDatabase disebut !!

Jadi setelah debugging saya menemukan bahwa hanya berlangganan yang dipanggil dan bukan fungsi penuh getContactsFromDatabase() karena breakpoint saya di srList.isRefreshing = true tidak dipicu. Hanya breakpoint di bagian berlangganan.

Saya juga mencoba menempatkan breakpoint ke satu-satunya bagian di mana fungsi getContactsFromDatabase dipanggil. Itu tidak pernah dipicu namun breakpoint dalam berlangganan dipicu.

Anda dapat memeriksa kode saya di Github

ContactListFragment.kt:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            dataStorage = DataStorage(requireContext())
            initView()
            initListeners()
        }

        private fun initView() {
            val layoutManager = LinearLayoutManager(activity)
            rvContact.layoutManager = layoutManager
            rvContact.itemAnimator = DefaultItemAnimator()
            adapter = ContactListAdapter(this::onContactClicked)
            rvContact.adapter = adapter
            getContacts()
        }

        private fun initListeners() {
            srList.setOnRefreshListener {
                viewModel.page = 1; viewModel.contacts.clear(); getContacts()
            }

            rvContact.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    val manager = rvContact.layoutManager as LinearLayoutManager
                    val visibleItemCount: Int = manager.childCount
                    val totalItemCount: Int = manager.itemCount
                    val firstVisibleItemPosition: Int = manager.findFirstVisibleItemPosition()
                    if (!srList.isRefreshing) {
                        if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                            && firstVisibleItemPosition >= 0
                            && totalItemCount >= ContactListViewModel.PAGE_SIZE
                        ) {
                            getContacts()
                        }
                    }
                }
            })
        }

        private fun getContacts() {
            srList.isRefreshing = true
            disposable.add(viewModel.getContactByPages()
                .doOnError { e ->
                    srList.isRefreshing = false
                    if (viewModel.launch){
                        Timber.e("get contacts database")//breakpoint not triggered
                        getContactsFromDatabase()
                    }
                    e.localizedMessage?.let {
                        Timber.e(it)
                    }
                    val message = when (e) {
                        is BadRequestException -> {
                            getString(R.string.common_error_bad_request)
                        }
                        is ServerErrorException -> {
                            getString(R.string.common_error_server_error)
                        }
                        is UnknownHostException -> {
                            getString(R.string.common_error_no_connection)
                        }
                        else -> {
                            getString(R.string.common_error_basic)
                        }
                    }
                    Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
                }
                .subscribe({ result ->
                    srList.isRefreshing = false
                    viewModel.page++
                    if (dataStorage.getBoolean(IS_FROM_CACHE)){//need a variable to clean the database after a first successful fetch
                        dataStorage.putBoolean(IS_FROM_CACHE, false).subscribe()
                        viewModel.contacts.clear()
                        cleanContactListOfDatabase()
                    }
                    viewModel.contacts.addAll(result.contacts)
                    saveContactsToDatabase()
                    adapter.updateList(viewModel.contacts)
                    tvNumberOfResult.text = getString(
                        R.string.contact_list_fragment_number_of_result,
                        viewModel.contacts.size
                    )
                }, Throwable::printStackTrace)
            )
        }

        private fun getContactsFromDatabase() {
            srList.isRefreshing = true//breakpoint not triggered here
            disposable.add(viewModel.getContactFromDatabase()
                .doOnError {
                    srList.isRefreshing = false
                }
                .subscribe({
                    srList.isRefreshing = false// breakpoint triggered here
                        viewModel.launch = false
                        viewModel.contacts.addAll(it)
                        adapter.updateList(viewModel.contacts)
                        tvNumberOfResult.text = getString(
                            R.string.contact_list_fragment_number_of_result,
                            viewModel.contacts.size
                        )
                        dataStorage.putBoolean(IS_FROM_CACHE, true).subscribe()
                }, Throwable::printStackTrace)
            )
        }

        private fun saveContactsToDatabase() {
            disposable.add(viewModel.insertAllContactsToDataBase()
                .doOnError {
                    Timber.e("Insert error")
                }
                .subscribe({
                    Timber.d("Contacts saved")
                }, Throwable::printStackTrace)
            )
        }

        private fun cleanContactListOfDatabase(){
            disposable.add(viewModel.cleanContactList()
                .doOnError {
                    Timber.e("clean table error")

                }
                .subscribe({
                    Timber.e("Table cleaned")
                }, Throwable::printStackTrace)
            )
        }

Untuk melanjutkan masalah, metode berlangganan viewModel.getContactFromDatabase() dipicu tanpa pemanggilan fungsi getContactsFromDatabase().
Buka aplikasi tanpa jaringan apa pun (ada kontak yang ditampilkan dari db lokal);
Buka jaringan apa saja (wifi atau 4g);
Coba segarkan gesek untuk menarik kontak dari API;
Langganan getContacts() dipicu (normal);
Langganan viewModel.getContactFromDatabase() dipicu bahkan tanpa pemanggilan fungsi getContactsFromDatabase() -- MASALAH

Anda dapat memeriksa kode saya di Github

1
Itoun 18 Juni 2020, 17:53

1 menjawab

Jawaban Terbaik

Berikut ini dokumen:

kamar/mengakses-data#query-rxjava

kamar-rxjava-acb0cd4f3757

Mengalir / Diamati

Setiap kali data pengguna diperbarui, objek Flowable akan muncul secara otomatis, memungkinkan Anda untuk memperbarui UI berdasarkan data terbaru.

Dalam kode Anda, setelah getContactByPages() Anda memanggil saveContactsToDatabase() untuk menyimpan data ke database

Jadi viewModel.getContactFromDatabase() (yang menunjuk ke ContactDao.getContacts()) akan memancarkan data lagi.

Jika Anda ingin ContactDao.getContacts() hanya memancarkan satu kali saat dipanggil, pertimbangkan untuk mengonversi ContactDao.getContacts() menjadi MayBe/Single alih-alih Observable

Semoga ini membantu.

1
justHooman 25 Juni 2020, 19:10