【问题标题】:How to implement material CircularProgressIndicator in kotlin [duplicate]如何在kotlin中实现材料CircularProgressIndicator [重复]
【发布时间】:2023-03-10 08:14:01
【问题描述】:

我试图在从服务器获取数据时显示CircularProgressIndicator,但我收到此错误root.findViewById(R.id.loadingbar) must not be null

逻辑

  1. 在获取数据之前隐藏回收站视图项
  2. 在获取数据时显示Circular Progress
  3. 当数据准备好时隐藏Circular Progress
  4. 显示回收站查看项目

代码

xml

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

    <!-- Circular progress indicator -->
    <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" />

    <!-- RecyclerView items -->
    <androidx.cardview.widget.CardView
        android:id="@+id/cardView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:elevation="8dp">

        <TextView
            android:id="@+id/order_Iid"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:gravity="start|top"
            android:text="@string/order_ID"
            android:textSize="12sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/order_status_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|start"
            android:layout_marginStart="5dp"
            android:layout_marginTop="35dp"
            android:text="@string/order_status"
            android:textColor="#5CDCBD"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/order_price_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top|end"
            android:layout_marginEnd="5dp"
            android:text="@string/price"
            android:textSize="12sp"
            android:textStyle="bold" />

    </androidx.cardview.widget.CardView>

</LinearLayout>

Fragment

对代码进行注释以便更好地理解

class OrdersFragment : Fragment() {

    lateinit var sesssion: SessionManager
    lateinit var laundriesRecycler: RecyclerView
    lateinit var progressBar: CircularProgressIndicator
    lateinit var cardView2: CardView

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

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val root = inflater.inflate(R.layout.fragment_orders, container, false)
        sesssion = SessionManager(context)
        laundriesRecycler = root.findViewById(R.id.orders_list)


        // get progress
        progressBar = root.findViewById(R.id.loadingbar)
        //get recycler item
        cardView2 = root.findViewById(R.id.cardView2)

        getOrders()
        return root
    }

    private fun getOrders() {

        //show progress
        progressBar.visibility = View.VISIBLE
        //hide items
        cardView2.visibility = View.GONE




        var session = SessionManager(context)
        session.checkLogin()
        var user = session.getUserDetails()
        var token: String? = user.get(SessionManager.KEY_ACCESS_TOKEN)
        val tokenFull = "Bearer $token"

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

        val stringReq : StringRequest =
                object : StringRequest(
                        Method.GET, url,
                        Response.Listener { response ->


                            // hide progress
                            progressBar.visibility = View.GONE
                            //show items
                            cardView2.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 ->
                            Toast.makeText(context, error.message, Toast.LENGTH_LONG)
                                    .show()
                        }
                ){
                    override fun getHeaders(): Map<String, String> {
                        val headers = HashMap<String, String>()
                        headers["Content-Type"] = "application/json"
                        headers["Authorization"] = tokenFull
                        return headers
                    }
                }
        queue.add(stringReq)
    }
}

有什么想法吗?

【问题讨论】:

  • 也许您应该考虑使用ViewBinding?它可以减少这些 NPE 错误
  • @Teo 怎么样?可以举个例子吗?
  • 另外,您可能需要将问题更改为root.findViewById(R.id.loadingbar) must not be null 以避免混淆。

标签: android kotlin material-design


【解决方案1】:

在你 build.gradle(app)

android{
    buildFeatures {
        viewBinding = true
        dataBinding = true
    }
}
// 1 - direct inflate the fragment layout into Fragment()
class OrdersFragment : Fragment(R.layout.fragment_orders) {

    // 2 - view binding
    private lateinit var binding: FragmentOrdersBinding
    lateinit var sesssion: SessionManager
    lateinit var laundriesRecycler: RecyclerView
    lateinit var progressBar: CircularProgressIndicator
    lateinit var cardView2: CardView

    // 3 - directly call onViewCreated() as the layout already inflated
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        
       // 4 - bind view to viewBinding variable
        binding = FragmentOrdersBinding.bind(view)
        sesssion = SessionManager(context)
        getOrders()
    }

    private fun getOrders() {
        
        // 5 - After that, basically every element just call binding to locate them
        //show progress
        binding.loadingBar.visibility = View.VISIBLE
        //hide items
        binding.cardView2.visibility = View.GONE

    }
}

【讨论】:

  • 找不到binding.loadingbar.visibility = View.VISIBLE loadingbar 是红色的
  • 你能试着输入binding.吗? IDE 会向您建议正确的值
  • 找不到。这是截图ibb.co/5rpmnRk
  • 尝试在您的 gradle 中添加 dataBinding = true。我认为它属于数据绑定而不是 viewBinding
  • 如果我只使用loadingBar.visibility = View.VISIBLE而不使用binding怎么办?
【解决方案2】:

已解决

特别感谢Teo 让我意识到这个问题。

修复

  1. 我不得不将我的进度添加到我的项目 xml 中,而不是将其添加到我的片段 xml 中,其中放置了我的回收站代码(#1 错误放置的代码)
  2. 使用绑定(与Teo提到的不同,不需要使用onViewCreated导致未定义的binding错误。而是应该在onCreateView函数中定义)这是最终代码
    private lateinit var binding: FragmentOrdersBinding
    
    override fun onCreateView(
      inflater: LayoutInflater, container: ViewGroup?,
      savedInstanceState: Bundle?
    ): View? {
      // Inflate the layout for this fragment
      val root = inflater.inflate(R.layout.fragment_orders, container, false)
      sesssion = SessionManager(context)
      laundriesRecycler = root.findViewById(R.id.orders_list)
      binding = FragmentOrdersBinding.bind(root) // <--here
      getOrders()
      return root
    }
    
    private fun getOrders() {
      binding.loadingBar.visibility = View.VISIBLE
      binding.ordersList.visibility = View.GONE
      
      // API process and flip those 2 lines above in success response to
      binding.loadingBar.visibility = View.GONE
      binding.ordersList.visibility = View.VISIBLE
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-16
    相关资源
    最近更新 更多