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

Kotlin中实现Material CircularProgressIndicator及空指针报错解决

根因排查

你触发root.findViewById(R.id.loadingbar) must not be null的核心原因是布局文件与代码引用完全不匹配,同时逻辑设计不符合RecyclerView的工作规则。

具体问题点

  • 你在onCreateView中通过inflater.inflate(R.layout.fragment_orders, container, false)加载的是Fragment根布局,但你贴出的、包含@+id/loadingbar和@+id/cardView2的XML内容,根本不是fragment_orders.xml,而是RecyclerView的单条列表项布局。
  • 你的fragment_orders.xml实际内容里,既没有定义@id/loadingbar,也没有定义@id/cardView2,甚至连代码中findViewById(R.id.orders_list)对应的RecyclerView控件都不存在,所有findViewById都会拿到null,直接触发空指针。
  • 你原本的设计逻辑存在偏差:你试图在Fragment中直接获取RecyclerView item内部的CardView控件、通过控制它的显隐来实现列表加载状态切换,但RecyclerView的item布局是被Adapter批量复用的,根本不属于Fragment根视图的一部分,这种写法本身就不符合RecyclerView的运行逻辑。

完整修复步骤

1. 拆分两类布局文件

(1)重写Fragment根布局 res/layout/fragment_orders.xml

这个布局才是你代码中inflate给root的视图,需要包含全局的进度条和RecyclerView:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- 全局加载进度条 -->
    <com.google.android.material.progressindicator.CircularProgressIndicator
        android:id="@+id/loadingbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:layout_gravity="center_horizontal|center_vertical" />

    <!-- 订单列表RecyclerView -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/orders_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</LinearLayout>

(2)保留列表项布局为 res/layout/item_order.xml

你之前写的带CardView、三个订单TextView的XML,直接保存为这个item布局即可,后续会交给Adapter复用,不需要在这里加任何全局控件。

2. 修正Fragment代码逻辑

  • 删除所有和cardView2相关的代码:这个控件属于item布局,根本无法通过Fragment的根视图直接findViewById获取。
  • 加载状态切换的控制对象从「item的CardView」换成「全局的RecyclerView和进度条」。
    修正后的核心代码片段:
class OrdersFragment : Fragment() {
    lateinit var session: SessionManager
    lateinit var laundriesRecycler: RecyclerView
    lateinit var progressBar: CircularProgressIndicator
    // 删掉 lateinit var cardView2: CardView 这行,完全用不到

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_orders, container, false)
        session = SessionManager(context)
        // 现在这两个控件都在fragment_orders.xml里,不会再返回null
        laundriesRecycler = root.findViewById(R.id.orders_list)
        progressBar = root.findViewById(R.id.loadingbar)

        getOrders()
        return root
    }

    private fun getOrders() {
        // 加载中:显示进度条,隐藏整个列表
        progressBar.visibility = View.VISIBLE
        laundriesRecycler.visibility = View.GONE

        val user = session.getUserDetails()
        val token = user.get(SessionManager.KEY_ACCESS_TOKEN)
        val tokenFull = "Bearer $token"

        val queue = Volley.newRequestQueue(context)
        val url = "https://example.com/api/orders"

        val stringReq = object : StringRequest(
            Method.GET, url,
            Response.Listener { response ->
                // 加载完成:隐藏进度条,显示列表
                progressBar.visibility = View.GONE
                laundriesRecycler.visibility = View.VISIBLE

                val list = Gson().fromJson(response, OrderArr::class.java)
                laundriesRecycler.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
                laundriesRecycler.adapter = OrdersAdapter(context, list)
            },
            Response.ErrorListener { error ->
                // 修复:加载失败也要隐藏进度条,避免一直转圈
                progressBar.visibility = View.GONE
                Toast.makeText(context, error.message, Toast.LENGTH_LONG).show()
            }
        ) {
            override fun getHeaders(): Map<String, String> {
                return mapOf(
                    "Content-Type" to "application/json",
                    "Authorization" to tokenFull
                )
            }
        }
        queue.add(stringReq)
    }
}

可选优化建议

  • 后续可以替换掉手动findViewById的写法,引入View Binding,彻底避免布局id写错、控件找不到的空指针问题。
  • 如果需要在空数据、加载失败的场景给用户展示提示,可以在根布局里再加一个全局的提示TextView,和进度条、RecyclerView做三者互斥的显隐控制即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 01:06:03