我的第一个观察者正确调用,但在 kotlin android 中将数据插入房间数据库后没有调用另一个观察者 建议/解决方案说明

如何解决我的第一个观察者正确调用,但在 kotlin android 中将数据插入房间数据库后没有调用另一个观察者 建议/解决方案说明

在应用程序中,我从网络和观察者更改方法中获取数据,将该数据插入到本地数据库中。没关系。但是插入到数据库后,我的第二个观察者没有被调用,所以我的 UI 不会更新。

ManActivity.class

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel
    private lateinit var adapter: MainAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layout.activity_main)
        setupViewModel()
        setupUI()
        setupObservers()
        setupObservers2()
    }


    private fun setupViewModel() {
        viewModel = ViewModelProviders.of(
            this,ViewModelFactory(ApiHelper(RetrofitBuilder.apiService))
        ).get(MainViewModel::class.java)
    }

    private fun setupUI() {
        recyclerView.layoutManager = LinearLayoutManager(this)
        adapter = MainAdapter(arrayListOf())
        recyclerView.addItemDecoration(
            DividerItemDecoration(
                recyclerView.context,(recyclerView.layoutManager as LinearLayoutManager).orientation
            )
        )
        recyclerView.adapter = adapter
    }

    private fun setupObservers() {
        viewModel.getUsers().observe(this,Observer {

            //viewModel.getUserFromWeb()
            it?.let { resource ->
               when (resource.status) {
                    SUCCESS -> {
                        Log.d("MYLOG","MyAPIChange success")
                        recyclerView.visibility = View.VISIBLE
                        progressBar.visibility = View.GONE
                        resource.data?.let {

                               users ->  viewModel.setUserListToDB(this,users)
                               //sleep(1000)
                           }

                    }
                    ERROR -> {
                        recyclerView.visibility = View.VISIBLE
                        progressBar.visibility = View.GONE
                        Log.d("MYLOG","MyAPIChange error")
                        Toast.makeText(this,it.message,Toast.LENGTH_LONG).show()
                    }
                    LOADING -> {
                        Log.d("MYLOG","MyAPIChange loading")
                        progressBar.visibility = View.VISIBLE
                        recyclerView.visibility = View.GONE
                    }
                }
            }
        })

    }

    private fun setupObservers2() {
        viewModel.getUserFromDB(this).observe(this,Observer {
                users -> retrieveList(users)
            Log.d("MYLOG","..MyDBChange")
        })
    }

    private fun retrieveList(users: List<User>) {
        adapter.apply {
            addUsers(users)
            notifyDataSetChanged()
        }
    }
}

MyViewModel.class

class MainViewModel(private val mainRepository: MainRepository) : ViewModel() {

    //lateinit var tempUser : MutableLiveData<List<User>>
    fun getUsers() = liveData(Dispatchers.IO) {
        emit(Resource.loading(data = null))
        try {
            emit(Resource.success(data = mainRepository.getUsers()))
        } catch (exception: Exception) {
            emit(Resource.error(data = null,message = exception.message ?: "Error Occurred!"))
        }
        //emit(mainRepository.getUsers())   //direct call
    }

    fun getUserFromDB(context: Context) = liveData(Dispatchers.IO) {
        emit(mainRepository.getUserList(context))
    }

    fun setUserListToDB(context: Context,userList: List<User>) {

        /*GlobalScope.launch {
            mainRepository.setUserList(context,userList)
        }*/

        CoroutineScope(Dispatchers.IO).launch {
            mainRepository.setUserList(context,userList)
        }

    }
}

MyRepository.class

class MainRepository(private val apiHelper: ApiHelper) {

    suspend fun getUsers() = apiHelper.getUsers()    // get from web

    companion object {

        var myDatabase: MyDatabase? = null

        lateinit var userList: List<User>

        fun initializeDB(context: Context): MyDatabase {
            return MyDatabase.getDataseClient(context)
        }

        /*fun insertData(context: Context,username: String,password: String) {

            myDatabase = initializeDB(context)

            CoroutineScope(Dispatchers.IO).launch {
                val loginDetails = User(username,password)
                myDatabase!!.myDao().InsertData(loginDetails)
            }

        }*/
    }
    //fun getUserList(context: Context,username: String) : LiveData<LoginTableModel>? {

    suspend fun getUserList(context: Context) : List<User> {

        myDatabase = initializeDB(context)
        userList = myDatabase!!.myDao().getUserList()
        Log.d("MYLOG=","DBREAD"+userList.size.toString())


         return userList
    }

    fun setUserList(context: Context,userList: List<User>){

        myDatabase = initializeDB(context)

        /*CoroutineScope(Dispatchers.IO).launch {
            myDatabase!!.myDao().InsertAllUser(userList)
            Log.d("MYLOG","MyDBInserted")
        }*/
        myDatabase!!.myDao().InsertAllUser(userList)
        Log.d("MYLOG","MyDBInserted")
        /*val thread = Thread {
            myDatabase!!.myDao().InsertAllUser(userList)
        }
        Log.d("MYLOG","MyDBInserted")
        thread.start()*/
    }
}

DAO 类

@Dao
interface DAOAccess {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun InsertAllUser(userList: List<User>)

//    @Query("SELECT * FROM User WHERE Username =:username")
//    fun getLoginDetails(username: String?) : LiveData<LoginTableModel>

    @Query("SELECT * FROM User")
    suspend fun getUserList() : List<User>
}

RetrofitBuilder

object RetrofitBuilder {

    private const val BASE_URL = "https://5e510330f2c0d300147c034c.mockapi.io/"

    private fun getRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val apiService: ApiService = getRetrofit().create(ApiService::class.java)
}

请你知道我在这里做错了什么以及为什么在插入到 db 后没有调用第二个观察者

实际上它是在屏幕启动时调用的,但当时没有插入数据,因此列表大小为 0,插入数据后,此方法不会再次调用。但是一旦我关闭应用程序并再次启动,数据将在启动时显示 bcoz,此方法调用和数据得到

解决方法

我没有足够的声望来commet,因此我只是在这个答案中提出了一个建议:

建议/解决方案

Room 支持开箱即用的 LiveData。所以在你的 DAO 中你可以改变

suspend fun getUserList() : List<User>

suspend fun getUserList() : LiveData<List<User>>

然后在您的存储库中调整为

suspend fun getUserList(context: Context) : LiveData<List<User>> {

        myDatabase = initializeDB(context)
        userList = myDatabase!!.myDao().getUserList()
        Log.d("MYLOG=","DBREAD"+userList.value.size.toString())


         return userList
    }

在视图模型中

fun getUserFromDB(context: Context) = mainRepository.getUserList(context))
    

通过这些调整,我认为它应该会奏效。

说明

您在这里使用了 liveData 协程构建器

fun getUserFromDB(context: Context) = liveData(Dispatchers.IO) {
        emit(mainRepository.getUserList(context))
    }

据我所知,这个构建器是为了执行一些异步/挂起任务,一旦这个任务完成,你创建的 liveData 就会发出结果。这意味着您只有一次收到用户列表的状态,然后将列表发送给观察者一次,然后这个 liveData 就完成了。它不会一直观察数据库中列表的变化。

这就是为什么它非常适合观察 API 调用(您想等到调用完成并发出一次响应),而不是观察 DB 状态(您想观察用户列表中的用户列表) DB 并在列表更改时向观察者发出更改)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res