无法使用 Kotlin 协程解析回收器视图中的数据

如何解决无法使用 Kotlin 协程解析回收器视图中的数据

我正在从服务器获取数据并尝试使用协程在回收器视图中解析它。虽然数据已成功获取,但我无法从嵌套的 json 中解析特定键。

这是 JSON 响应:

{
"status": "200","message": "Success","result": [
    {
        "_id": "60f516fa846e059e2f19c50c","category": "Shirts","sku": [
            {
                "name": "Oxford shirt","brand": "John players","price": "25","color": "Blue","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi1.jpg?alt=media&token=64779194-e3b5-484f-a610-c9a20648b64c"
            },{
                "name": "Buttoned down","brand": "Gap originals","price": "45","color": "Pink","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi2.jpg?alt=media&token=0b207b90-f1bc-4771-b877-809648e6bdc1"
            },{
                "name": "Collared","brand": "Arrow","price": "30","color": "White","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi3.jpg?alt=media&token=2c1bb3f8-e739-4f09-acbc-aa11fed795e3"
            },{
                "name": "Printed","color": "Olive green","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi4.jpg?alt=media&token=666f94bf-4769-44fe-a909-3c81ca9262f7"
            },{
                "name": "Hoodie","brand": "Levis","price": "44","color": "Yellow","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi5.jpg?alt=media&token=65fccef4-a882-4278-b5df-f00eb2785bf1"
            }
        ]
    },{
        "_id": "60f51c37846e059e2f19c50f","category": "Shoes","sku": [
            {
                "name": "Sneakers","brand": "Puma","price": "35","color": "Black and white","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho1.jpg?alt=media&token=d078988d-9e85-4313-bb4a-c9d46e09f0b9"
            },{
                "name": "Running shoe","brand": "Nike","price": "99","color": "Multicolor","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho2.jpg?alt=media&token=ed2e7387-3cf6-44df-9f7d-69843eb0bcdf"
            },{
                "name": "Yezzy","brand": "Adidas","price": "349","color": "Gray","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho3.jpg?alt=media&token=2c37ef76-37bb-4bdd-b36c-dea32857291f"
            },{
                "name": "Sneakers","price": "79","color": "Black","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho4.jpg?alt=media&token=4acd763e-8b93-47cd-ba45-92f34af4cf83"
            },{
                "name": "Joyride running","price": "80","img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho5.jpg?alt=media&token=e3780dcc-52cb-49d5-9791-e0a44870716c"
            }
        ]
    
       }
    ]
}

我想获取类别

下面是数据类

Product.kt

data class Product(
  val message: String,val result: List<Result>,val status: String
)

结果.kt

data class Result(
  val _id: String,val category: String,val sku: List<Sku>
)

ApiService.kt

interface ApiService {

  @GET("getProducts")
  suspend fun getCategories(): Response<Product>
}

CategoriesViewModel.kt

class CategoriesViewModel: ViewModel() {

private var categoryList: MutableLiveData<List<Result>> = MutableLiveData()

fun getAllCategory(): LiveData<List<Result>> {

    viewModelScope.launch(Dispatchers.IO) {

        val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
        val response = retrofit.getCategories()

        if (response.isSuccessful) {
            categoryList.postValue(response.body()!!.result)
        }
    }
    return categoryList
  }
}

CategoryAdapter.kt

class CategoryAdapter(private val context: Context,private val categories:List<Result>): RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): CategoryAdapter.ViewHolder {
   return ViewHolder(ParentRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}

override fun onBindViewHolder(holder: ViewHolder,position: Int) {

    val model = categories[position]
    holder.binding.catTitle.text = model.category
}

override fun getItemCount(): Int {
    return categories.size
}

class ViewHolder(val binding:ParentRowBinding): RecyclerView.ViewHolder(binding.root)
}

HomeFragment.kt

class HomeFragment : Fragment() {

private var binding: FragmentHomeBinding? = null
private lateinit var adapter: CategoryAdapter

override fun onCreateView(
    inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    binding = FragmentHomeBinding.inflate(inflater,container,false)

    binding!!.parentRecycler.setHasFixedSize(true)
    binding!!.parentRecycler.layoutManager = LinearLayoutManager(activity)

    val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)

    viewModel.getAllCategory().observe(viewLifecycleOwner,Observer { t ->

        val len = t.size

        if(len > 0){

            for(i in 0 until len){
                Log.d("hell",t[i].category.toString())
            }
        }
    })

    return binding!!.root
}

override fun onDestroy() {
    super.onDestroy()
    binding = null
}
}

在这里,我以某种方式获取了类别,但我不知道如何将其传递给适配器,以便我可以在 recyclerview 中显示它。

解决方法

您必须为 Adapter 观察者内的 RecyclerView 分配一个 getAllCategory,如下所示

viewModel.getAllCategory().observe(viewLifecycleOwner,Observer {
    if(!it.isNullOrEmpty()){
        binding!!.parentRecycler.adapter = CategoryAdapter(requireContext(),it)
        // This will bind the Result list received to the recycler view
    }
})
,

在您的 HomeFragment 中,您需要将适配器设置为 RecyclerView

 binding!!.parentRecycler.adapter= CategoryAdapter(requireContext(),t) 

HomeFragment 的完整代码如下

class HomeFragment : Fragment() {

private var binding: FragmentHomeBinding? = null
private lateinit var adapter: CategoryAdapter

override fun onCreateView(
    inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    binding = FragmentHomeBinding.inflate(inflater,container,false)

    binding!!.parentRecycler.setHasFixedSize(true)
    binding!!.parentRecycler.layoutManager = LinearLayoutManager(activity)

    val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)

    viewModel.getAllCategory().observe(viewLifecycleOwner,Observer { t ->

        val len = t.size

        if(len > 0){
            //add this line
            binding!!.parentRecycler.adapter= CategoryAdapter(requireContext(),t) 

            for(i in 0 until len){
                Log.d("hell",t[i].category.toString())
            }
        }
    })

    return binding!!.root
}

override fun onDestroy() {
    super.onDestroy()
    binding = null
}
}
,

我想最好的方法是从 ListAdapter 继承您的适配器。因为与 RecyclerView.Adapter 不同,它内置支持提交新列表。

这更高效、更快捷,并且不需要创建新的适配器对象或完全更新 RecyclerView 中的所有项目。由于 DiffUtil,只有实际更改的项目才会更新。

所以你CategoryAdapter应该变成:

class CategoryAdapter : ListAdapter<Result,CategoryAdapter.ViewHolder>(DIFF_CALLBACK) {

    companion object {
        val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Result>() {
            override fun areItemsTheSame(oldItem: Inspection.Type,newItem: Inspection.Type) = oldItem._id == newItem._id
            override fun areContentsTheSame(oldItem: Inspection.Type,newItem: Inspection.Type) = oldItem == newItem
        }
    }

override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): CategoryAdapter.ViewHolder {
   return ViewHolder(ParentRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}

override fun onBindViewHolder(holder: ViewHolder,position: Int) {

    val model = getItem(position)
    holder.binding.catTitle.text = model.category
}

class ViewHolder(val binding:ParentRowBinding): RecyclerView.ViewHolder(binding.root)
}

在你的 onCreateView 中:

override fun onCreateView(
    inflater: LayoutInflater,false)

    binding!!.parentRecycler.setHasFixedSize(true)
    binding!!.parentRecycler.layoutManager = LinearLayoutManager(activity)
    adapter = CategoryAdapter()
    binding!!.parentRecycler.adapter = adapter

    val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)

    viewModel.getAllCategory().observe(viewLifecycleOwner,Observer { categories ->
        adapter.submitList(categories)
    })

    return binding!!.root
}

请注意,在上面的代码中,您根本没有创建适配器实例,也没有将其分配给回收者。所以它根本不会显示任何东西。

在我的示例中,我在 onCreateView 中创建了一个适配器并将其分配给回收者。在 Observer 中,我们将从 ViewModel 接收到的数据传递给适配器。

,

是的,正如@dhiraj-uchil 所提到的,这里的问题不是设置缺少的适配器。我也会使 binding 延迟或本地。我也会提取 context,并在其他地方使用它。

 val binding = FragmentHomeBinding.inflate(inflater,false)
 val context = requireContext()
 binding.parentRecycler.adapter= CategoryAdapter(context,t) 

关于从 JSON 制作数据类对象,我制作了一个工具,其中包括生成这样的类:

https://kt.academy/json

enter image description here

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

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地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-