android - Android RxJava订阅无处触发

标签 android kotlin mvvm android-room rx-java2

我有一个简单的应用程序,显示从API提取的联系人列表。
如果应用启动时没有网络,则需要显示最新的联系人提取。因此,这就是为什么我与Room一起将联系人保存到数据库中的原因。

触点已正确保存,需要时可将其正确拉出。
但是,当我执行以下模式时,会出现一个奇怪的问题:
-我从API中提取了一些联系人(自动保存到本地数据库中)
-我杀了这个应用;
-我切断了所有网络以触发从本地数据库的拉取;
-我在没有任何网络的情况下启动了该应用程序,可以从本地数据库正确显示联系人;
-我打开网络来处理对API的新调用(清理数据库等)。
-在响应对API的调用之后,在getContacts调用的订阅之后,getContactsFromDatabase的订阅被称为!!!

因此,在调试之后,我发现仅调用了预订,而不调用完整功能getContactsFromDatabase(),因为没有触发我在srList.isRefreshing = true上的断点。订阅部分中只有断点。

我还尝试在仅调用getContactsFromDatabase函数的部分设置一个断点。它从未触发过,但是订阅中的断点已触发。

您可以在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)
            )
        }


要恢复该问题,无需调用viewModel.getContactFromDatabase()函数即可触发getContactsFromDatabase()的subscription方法。
打开没有任何网络的应用程序(本地数据库显示联系人);
打开任何网络(WiFi或4g);
尝试滑动刷新以从API中提取联系人;
触发getContacts()的订阅(正常);
甚至不调用函数viewModel.getContactFromDatabase()即可触发getContactsFromDatabase()的订阅-问题

您可以在Github上检查我的代码

最佳答案

遵循这些文档:
room/accessing-data#query-rxjava
room-rxjava-acb0cd4f3757

Flowable/Observable

Every time the user data is updated, the Flowable object will emit automatically, allowing you to update the UI based on the latest data.


在代码中,在getContactByPages()之后,您调用saveContactsToDatabase()将数据保存到数据库
因此viewModel.getContactFromDatabase()(指向ContactDao.getContacts())将再次发出数据。
如果您希望ContactDao.getContacts()在被调用时仅发出一次,请考虑将ContactDao.getContacts()转换为MayBe/Single而不是Observable希望这可以帮助。

关于android - Android RxJava订阅无处触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62452860/

相关文章:

c# - MVVM 列表和 ObservableCollection

Xamarin Forms Switch Toggled 事件未与 View 模型绑定(bind)

android - 无法使用谷歌 SDK 在 Android 上转换 AdMob 广告

spring-boot - SpringBoot 中的 Kotlin - `init` block 的初始化顺序

swift - Kotlin 等价于 Swift 期望/ promise

android - Kotlin:如果网络断开连接,使用 ConnectivityManager 检查网络状态将返回 null。怎么来的?

javascript - Web应用程序使用Redux,如何处理逻辑只需要执行一次

方向更改后,Android 找不到 fragment View

java - Sharedpreference 似乎不起作用,无法显示存储的数据

android - 如何在android中的gradle中动态启用 flavor