You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio 2023:如何正确将Retrofit响应列表传入Adapter?

问题:Retrofit获取数据后无法在RecyclerView显示列表

通过Retrofit成功获取API响应(日志验证响应体内容正确),但将数据传入使用DiffUtils的Adapter后,RecyclerView始终为空。仅在Adapter构造时传入列表能正常显示,但希望通过submitList的方式实现数据更新。


MainActivity代码

class QuizMainActivity : AppCompatActivity() {

    private lateinit var quizCategoryAdapter: QuizCategoryAdapter
    private lateinit var binding: ActivityQuizMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityQuizMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        hideactionbar()

       setupRecyclerView()

        lifecycleScope.launchWhenCreated {
            val response = try{
                RetrofitInstance.api.getQuizCategories()
            }catch (e:IOException){
                Log.d("QuizCatTag", "IOException"+e)
                return@launchWhenCreated
            }catch (e: HttpException){
                Log.d("QuizCatTag", "HTTPException"+e)
                return@launchWhenCreated
            }

            if(response.isSuccessful && response.body()!=null){

                setupRecyclerView()
               quizCategoryAdapter.quizCategoryList = response.body()!!.category_detail // 传入响应列表到Adapter的位置

                Log.d("quizCategoryList", quizCategoryAdapter.quizCategoryList.toString() )

            }else{
            Log.d("TASG", "Response not successful")
        }
        }
    }

    private fun hideactionbar() {
        supportActionBar?.hide()
    }

    private fun setupRecyclerView() = binding.quizCategoryRv.apply {
       quizCategoryAdapter = QuizCategoryAdapter(this@QuizMainActivity)
        adapter = quizCategoryAdapter
        layoutManager = LinearLayoutManager(this@QuizMainActivity)
    }
}

Adapter代码(使用DiffUtils处理数据变更)

class QuizCategoryAdapter(
    private val context: Context
) : RecyclerView.Adapter<QuizCategoryAdapter.QuizCategoryHolder>() {

    private val diffCallBack = object: DiffUtil.ItemCallback<CategoryDetail>(){
        override fun areItemsTheSame(oldItem: CategoryDetail, newItem: CategoryDetail): Boolean {
            return oldItem.category_name == newItem.category_name
        }

        override fun areContentsTheSame(oldItem: CategoryDetail, newItem: CategoryDetail): Boolean {
            return oldItem == newItem
        }

    }
    private val differ = AsyncListDiffer(this, diffCallBack)

    var quizCategoryList : List<CategoryDetail>
        get() = differ.currentList
        set(value) {differ.submitList(value)}
  
    val textList  = quizCategoryList.chunked(3)

      
    class QuizCategoryHolder(binding: QuizCategoryItemBinding) : RecyclerView.ViewHolder(binding.root){
   
         val listTextV = listOf(binding.qciTv1, binding.qciTv2, binding.qciTv3)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuizCategoryAdapter.QuizCategoryHolder {
        return QuizCategoryHolder(QuizCategoryItemBinding.inflate(LayoutInflater.from(context), parent,false))
    }

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

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

     
        for (i in 0 until textList[position].size){
            if(textList[position][i].category_name==""){
                holder.listTextV[i].isVisible = false
            }else{
                holder.listTextV[i].text = textList[position][i].category_name
            }

        }


            holder.itemView.setOnClickListener{
                val intent = Intent(context, QuizQuestionActivity::class.java)
                context.startActivity(intent)
            }

    }

}

问题分析与解决方案

核心问题

  1. textList未动态更新:原代码中textList是普通val属性,仅在Adapter初始化时基于空列表执行一次chunked(3),后续quizCategoryList更新时,textList不会重新计算,导致getItemCount()始终返回0,RecyclerView无内容。
  2. 重复创建Adapter:MainActivity请求成功后重复调用setupRecyclerView(),会重新创建Adapter实例,覆盖原quizCategoryAdapter引用,导致数据传入的是新的空Adapter。

修复步骤

1. 将textList改为计算属性

修改Adapter中的textList定义,确保每次访问时都基于最新的列表重新分块:

val textList: List<List<CategoryDetail>>
    get() = quizCategoryList.chunked(3)

2. 移除MainActivity中重复的setupRecyclerView()调用

在请求成功的代码块中删除重复的初始化方法,保留原有的Adapter引用:

if(response.isSuccessful && response.body()!=null){
    // 移除该行:setupRecyclerView()
    quizCategoryAdapter.quizCategoryList = response.body()!!.category_detail
    Log.d("quizCategoryList", quizCategoryAdapter.quizCategoryList.toString() )
}

3. 验证CategoryDetail的equals()实现

如果CategoryDetail不是Kotlin数据类,需要手动实现equals()方法,否则DiffUtils的areContentsTheSame无法正确判断内容是否变化。数据类会自动生成该方法,无需额外处理。

4. 优化onBindViewHolder逻辑(可选)

避免索引越界风险,优化视图显示逻辑:

override fun onBindViewHolder(holder: QuizCategoryHolder, position: Int) {
    val currentChunk = textList[position]
    // 先重置所有TextView可见性
    holder.listTextV.forEach { it.isVisible = true }
    
    // 填充当前chunk的内容
    currentChunk.forEachIndexed { index, category ->
        if (category.category_name.isBlank()) {
            holder.listTextV[index].isVisible = false
        } else {
            holder.listTextV[index].text = category.category_name
        }
    }
    
    // 隐藏超出chunk长度的TextView
    for (i in currentChunk.size until holder.listTextV.size) {
        holder.listTextV[i].isVisible = false
    }

    holder.itemView.setOnClickListener{
        val intent = Intent(context, QuizQuestionActivity::class.java)
        context.startActivity(intent)
    }
}

内容的提问来源于stack exchange,提问作者Dhruv194

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:02:08