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

Fragment内RecyclerView获取API数据后无法刷新显示问题

问题:DialogFragment中RecyclerView获取数据后无法显示

我在Fragment中获取API响应结果后填充RecyclerView,已成功获取到数据,但数据始终无法显示在屏幕上。

空白的RecyclerView界面

请问我遗漏了什么?

MainActivity启动Fragment的代码:

// 生成API客户端
val client = RestClient(endpoint, TimeoutType.LONG_TIMEOUT)

// 生成对话框
val dialog = AccessHistoryFragment.newInstance(client)
dialog.isCancelable = true
dialog.show(supportFragmentManager, AccessHistoryFragment::class.java.name)

Fragment代码:

class AccessHistoryFragment: DialogFragment()
{
    private lateinit var context: Context
    private lateinit var progressBar: ProgressBar
    private lateinit var noResultsTv: AppCompatTextView
    private lateinit var accessHistoryRv: RecyclerView
    private lateinit var adapter: AccessHistoryRecyclerViewAdapter
    private lateinit var client: RestClient
    private var elements = mutableListOf<Access>()

    companion object
    {
        fun newInstance(client: RestClient): AccessHistoryFragment
        {
            val fragment = AccessHistoryFragment()
            fragment.client = client
            return fragment
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
    {
        // 获取视图
        val view = layoutInflater.inflate(R.layout.fragment_access_history, null) as View
        progressBar = view.findViewById(R.id.loading_bar) as ProgressBar
        accessHistoryRv = view.findViewById(R.id.access_history_rv) as RecyclerView
        noResultsTv = view.findViewById(R.id.no_results_tv) as AppCompatTextView
        context = view.context

        // 初始化RecyclerView
        generateRecyclerView()

        // 构建对话框
        val builder = AlertDialog.Builder(activity)
        builder.setView(view)
        return builder.create()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        cargarHistorial()
    }

    private fun generateRecyclerView()
    {
        try
        {
            adapter = AccessHistoryRecyclerViewAdapter(elements)
            accessHistoryRv.apply {
                this.layoutManager = LinearLayoutManager(context)
                this.adapter = adapter
            }
        }
        catch (ex: Exception) { dismiss() }
    }

    private fun cargarHistorial()
    {
        Thread {
            try
            {
                val history = client.getAccessHistory(DateHelper.getCurrentDate())
                updateAccessHistory(history)
            }
            catch (ex: Exception) { dismiss() }
        }.start()
    }

    private fun updateAccessHistory(accessList: MutableList<Access>)
    {
        requireActivity().runOnUiThread {
            progressBar.visibility = View.GONE
            if (accessList.size > 0)
            {
                elements.addAll(accessList)
                adapter.notifyItemRangeInserted(0, accessList.size)
                accessHistoryRv.visibility = View.VISIBLE
            }
            else noResultsTv.visibility = View.VISIBLE
        }
    }
}

Adapter代码:

class AccessHistoryRecyclerViewAdapter(private var elements: MutableList<Access>): RecyclerView.Adapter<AccessHistoryRecyclerViewAdapter.AccessHistoryViewHolder>()
{
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccessHistoryViewHolder
    {
        return AccessHistoryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.access_item, parent, false))
    }

    override fun onBindViewHolder(holder: AccessHistoryViewHolder, position: Int)
    {
        // 保存当前数据
        holder.access = elements[position]

        // 初始化视图内容
        holder.accessText.text = holder.access.toString()
    }

    // 返回列表长度
    override fun getItemCount() = elements.size

    inner class AccessHistoryViewHolder(v: View) : RecyclerView.ViewHolder(v)
    {
        var accessText: TextView = v.findViewById(R.id.access_text)
        lateinit var access: Access
    }
}

补充说明
改用ListView替代RecyclerView时功能正常:

val accessHistoryLv = view.findViewById(R.id.access_history_lv) as ListView
val elements = accessList.map { elem -> elem.toString() }
val adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, elements)
accessHistoryLv.adapter = adapter
accessHistoryLv.visibility = View.VISIBLE

解决方案

问题出在DialogFragment的RecyclerView没有获取到正确的布局尺寸约束,核心原因是视图inflate方式不规范,导致RecyclerView无法正常测量自身大小。

修复步骤:

  1. 修正视图inflate逻辑
    在onCreateDialog中inflate布局时,传入父容器并设置attachToRoot=false,让布局能继承对话框的约束:
// 原代码
val view = layoutInflater.inflate(R.layout.fragment_access_history, null) as View
// 修改为
val view = layoutInflater.inflate(R.layout.fragment_access_history, null, false) as View
// 或者更规范的写法:
val parent = LinearLayout(activity)
val view = layoutInflater.inflate(R.layout.fragment_access_history, parent, false)
  1. 检查RecyclerView的布局属性
    确保fragment_access_history.xml中的RecyclerView设置了明确的宽高:
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/access_history_rv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone"/>
  1. 验证数据通知方式
    如果不确定插入位置,可先用notifyDataSetChanged快速验证(后续再优化为更高效的notifyItemRangeInserted):
// 原代码
adapter.notifyItemRangeInserted(0, accessList.size)
// 替换为
adapter.notifyDataSetChanged()

为什么ListView能正常工作?

ListView内部自带自适应尺寸的逻辑,即使父容器约束不明确也能自行计算大小;而RecyclerView依赖明确的布局参数才能完成测量和渲染,这就是两者表现不同的核心原因。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:52:49