Android 改装呼叫,在MessageQueue中被阻止

Android 改装呼叫,在MessageQueue中被阻止,android,retrofit,android-room,kotlin-coroutines,coroutine,Android,Retrofit,Android Room,Kotlin Coroutines,Coroutine,我希望有一个系统可以使用缓存(在房间内)调用API(改装),只使用协同路由(没有LiveData和NetworkBoundResource) 因此,我们的工作流程是: 检查数据库中的数据 如果有,请出示 如果没有: 调用API 在数据库中保存数据 显示数据 问题应用程序在“调用API”步骤中被阻止,这里是堆栈 nativePollOnce:-1,MessageQueue(android.os)下一个:326,MessageQueue (android.os)loop:160,Looper(a

我希望有一个系统可以使用缓存(在房间内)调用API(改装),只使用协同路由(没有LiveData和NetworkBoundResource)

因此,我们的工作流程是:

  • 检查数据库中的数据
  • 如果有,请出示
  • 如果没有:
  • 调用API
  • 在数据库中保存数据
  • 显示数据
  • 问题应用程序在“调用API”步骤中被阻止,这里是堆栈

    nativePollOnce:-1,MessageQueue(android.os)下一个:326,MessageQueue (android.os)loop:160,Looper(android.os)main:6669,ActivityThread (android.app)invoke:-1,方法(java.lang.reflect)run:493, RuntimeInit$MethodAndArgsCaller(com.android.internal.os)main:858, ZygoteInit(com.android.internal.os)

    改装服务:

    interface ProductService {
        @GET("products")
        suspend fun getProducts(): Response<List<Product>>
    }
    

    这不是干净的架构。您应该有一个数据库层(您拥有的)、一个存储库和一个Viewmodel。所以,当framgnet被创建时,调用viewmodel来观察存储库中的数据,存储库也会观察数据库中的数据。如果来自db的数据是空的,那么它将在一个协程作用域中创建api调用,并在同一线程中将数据保存到db。因此,viewmodel会自动获得新数据的通知

    我建议使用MVVM设计模式。您必须在存储库模式中执行您想要的操作

    存储库模式是一种隔离数据源的设计模式 从应用程序的其余部分。存储库在数据源之间进行调解 (如持久模型、web服务和缓存)以及 应用程序。下图显示了应用程序组件(如活动)是如何运行的 使用LiveData的用户可以通过 存储库。要实现存储库,请使用存储库类, 例如在下一个任务中创建的VideosRepository类。 repository类将数据源与数据库的其余部分隔离开来 并提供一个干净的API,用于访问应用程序其余部分的数据。 使用存储库类是推荐的代码最佳实践 分离和架构。使用存储库的优点。A. 存储库模块处理数据操作,并允许您使用 多个后端。在典型的真实应用程序中,存储库 实现用于决定是否从网络获取数据的逻辑 或者使用缓存在本地数据库中的结果。这有助于提高效率 您的代码模块化且可测试。您可以轻松地模拟存储库 并测试代码的其余部分

    我建议您检查一下错误代码

    @Dao
    interface ProductDao {
    
        @Query("SELECT * FROM Product ORDER BY price")
        suspend fun getProducts(): List<Product>
    
        @Transaction
        @Insert(entity = Product::class)
        suspend fun insertProducts(products: List<Product>)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    
        productService = createProductService()
        productDao = MyDatabase.getDatabase(requireContext()).productDao()
        CoroutineScope(Dispatchers.Main).launch {
            getProducts()
        }
    }
    
    private suspend fun getProducts() {
        progressBar.visibility = View.VISIBLE
        recyclerViewProducts.visibility = View.GONE
        
        var products = withContext(Dispatchers.IO){ productDao.getProducts() }
    
        if(products.isEmpty()) {
    
            val response = withContext(Dispatchers.IO) { productService.getProducts() }
            if(response.isSuccessful && response.body() != null) {
                products = response.body()!!
                withContext(Dispatchers.IO) { productDao.insertProducts(products) }
            }
        }
    
        withContext(Dispatchers.Main) {
            progressBar.visibility = View.GONE
            recyclerViewProducts.visibility = View.VISIBLE
    
            recyclerViewProducts.apply {
                layoutManager = LinearLayoutManager(context)
                // set the custom adapter to the RecyclerView
                adapter = ProductsAdapter(products, this@ListProductFragment)
            }
        }
    }