java - 为什么 RecyclerView 在其他 Kotlin Android 之前加载

标签 java android kotlin android-fragments android-recyclerview

你好,我正在为我的作业做一个小应用程序,我想在应用程序上显示来 self 的 php api 的数据。但是 Recycler View 发送此消息 2022-04-25 00:41:36.662 13593-13593/net.robcorp.finalapp E/RecyclerView: 没有连接适配器;在适配器代码运行之前跳过布局,因为此消息 2022-04-25 00:41:36.907 13593-13593/net.robcorp.finalapp I/System.out: [Drivers(pos=1, name =Charles Leclerc, nb=16, points=71, title=Ferrari), Drivers(pos=2, name=Esteban Ocon, nb=31, points=20, title=Alpine)] 显示在上一个之后一个并且假设在适配器之前运行。 这是 DriversFragment.kt:

package net.robcorp.finalapp

import android.content.Context
import android.graphics.Insets.add
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.OneShotPreDrawListener.add
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import net.robcorp.finalapp.R
import net.robcorp.finalapp.databinding.FragmentDriversBinding
import net.robcorp.finalapp.drivers.DriverFragmentAdapter
import net.robcorp.finalapp.drivers.Drivers
import org.json.JSONArray


class DriversFragment : Fragment(R.layout.fragment_drivers) {

    private lateinit var recyclerView: RecyclerView
    private lateinit var myAdapter: DriverFragmentAdapter;
    lateinit var binding: FragmentDriversBinding
    private val drivers = ArrayList<Drivers>()
    val url = "https://robcorp.net/f1api/getdrivers.php"

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = FragmentDriversBinding.inflate(layoutInflater)
        recyclerView = binding.driversRecyclerView
        recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
        myAdapter = DriverFragmentAdapter(drivers)
        recyclerView.adapter = myAdapter
        println("adapter loaded")
        downloadDrivers()
    }

    fun downloadDrivers() {
        val task = Volley.newRequestQueue(this.context)
        val request = StringRequest(Request.Method.GET, url, {
                response ->
            val data = response.toString()
            val jArray = JSONArray(data)
//            Log.e("Error",response.toString())
            for (i in 0..jArray.length()-1) {
                val json_data = jArray.getJSONObject(i)
//                Log.e("Jobject",json_data.toString())
                val pos = i+1
                val name = json_data.getString("Name")
                val nb = json_data.getString("NB")
                val points = json_data.getString("Points")
                val title = json_data.getString("Title")
                val driver = Drivers(pos, name, nb, points, title)
                drivers.add(driver)

            }
            println(drivers)
            myAdapter.notifyDataSetChanged()
        }, {
                error ->
            println(error)
        })
        task.add(request)
    }
}

这是 DriverFragmentAdapter.kt:

package net.robcorp.finalapp.drivers

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import net.robcorp.finalapp.R
import net.robcorp.finalapp.databinding.DriverListBinding

class DriverFragmentAdapter(private var driversList: List<Drivers>): RecyclerView.Adapter<DriverFragmentAdapter.MyViewHolder>() {

    class MyViewHolder(val binding: DriverListBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(driver: Drivers) {
            val context = itemView.context
            val pos = itemView.findViewById<TextView>(R.id.driver_position)
            val bar = itemView.findViewById<TextView>(R.id.driver_bar)
            val name = itemView.findViewById<TextView>(R.id.driver_name)
            val nb = itemView.findViewById<TextView>(R.id.driver_number)
            val team = itemView.findViewById<TextView>(R.id.driver_team)
            val points = itemView.findViewById<TextView>(R.id.driver_points)

            pos.text = driver.pos.toString()
            name.text = driver.name
            nb.text = driver.nb
            team.text = driver.title
            points.text = driver.points

            if (driver.title == "Ferrari") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.ferrari_bar)
            } else if (driver.title == "Alpine") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.alpine_bar)
            } else if (driver.title == "Red Bull") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.redbull_bar)
            } else if (driver.title == "Mercedes") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.mercedes_bar)
            } else if (driver.title == "McLaren") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.mclaren_bar)
            } else if (driver.title == "Alfa Romeo") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.alfaromeo_bar)
            } else if (driver.title == "AlphaTauri") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.alphatauri_bar)
            } else if (driver.title == "Williams") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.williams_bar)
            } else if (driver.title == "Aston Martin") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.astonmartin_bar)
            } else if (driver.title == "Haas") {
                bar.background = ContextCompat.getDrawable(context, R.drawable.haas_bar)
            }
        }
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return MyViewHolder(DriverListBinding.inflate(LayoutInflater.from(parent.context)))

    }

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

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val driver = driversList[position]
        holder.binding.apply {
            println("je suis dans le binding")
            holder.bind(driver)
        }
    }

    fun setDriversList(driversList: List<Drivers>) {
        this.driversList = driversList
        notifyDataSetChanged()
    }

}

fragment 驱动程序.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- TODO: Update blank fragment layout -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/primary"
            android:orientation="vertical"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginBottom="10dp">

            <TextView
                android:id="@+id/calendar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="30dp"
                android:layout_marginTop="20dp"
                android:layout_marginEnd="30dp"
                android:layout_marginBottom="20dp"
                android:fontFamily="@font/marianneb"
                android:text="Pilotes"
                android:textAlignment="center"
                android:textColor="@color/white"
                android:textSize="25sp" />

        </LinearLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/drivers_recycler_view"
            android:scrollbars="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintTop_toBottomOf="@+id/header"/>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

驱动程序列表.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="20dp"
    android:layout_marginTop="10dp"
    android:layout_marginEnd="20dp"
    android:elevation="8dp"
    android:orientation="horizontal"
    android:padding="10dp"
    android:background="@drawable/rectangle">

    <TextView
        android:id="@+id/driver_position"
        android:layout_width="30dp"
        android:layout_height="match_parent"
        android:fontFamily="@font/marianneb"
        android:text="1"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textAlignment="center"/>

    <ImageView
        android:id="@+id/driver_bar"
        android:layout_width="20px"
        android:layout_height="match_parent"
        android:background="@drawable/ferrari_bar"/>



    <LinearLayout
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/driver_name"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:fontFamily="@font/marianneb"
            android:text="Charles Leclerc"
            android:textColor="@color/black"
            android:textSize="15sp"
            android:layout_marginStart="10dp"/>

        <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

            <TextView
                android:id="@+id/driver_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginTop="2.5dp"
                android:fontFamily="@font/mariannem"
                android:text="16"
                android:textColor="@color/black"
                android:textSize="10sp" />

            <TextView
                android:id="@+id/driver_team"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginTop="2.5dp"
                android:fontFamily="@font/mariannem"
                android:text="Ferrari"
                android:textColor="@color/black"
                android:textSize="10sp" />

        </LinearLayout>

    </LinearLayout>

    <TextView
        android:id="@+id/driver_points"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:fontFamily="@font/marianneb"
        android:text="578"
        android:textColor="@color/black"
        android:textSize="25sp"/>



</LinearLayout>

最佳答案

这是一个无害的警告。由于您的 RecyclerView 已经在布局中,它会在您的 View 层次结构可见时尝试绘制它,发现没有分配适配器,因此它只是发出警告而不绘制它。

也许创建您的适配器(使用空列表)并在膨胀 View 时立即分配它,并在数据准备好时更新其列表可能会更干净。

顺便说一下,在onCreate 中膨胀你的布局是不正确的。这应该在 onCreateView 中完成。


编辑:

此处的代码将布局膨胀两次,一次用于变量 v,一次用于 binding 属性。首先,没有理由给它充气两次。其次,由于您使用 v 作为 onCreateView 的返回值,因此您对 binding 中的 View 所做的任何操作都是毫无意义的,对实际显示在屏幕上的 View 。

    val v = inflater.inflate(R.layout.fragment_drivers, container, false)
    binding = FragmentDriversBinding.inflate(layoutInflater)
    // ...
    return v

您应该只膨胀一次 View (使用绑定(bind))并返回绑定(bind)的 View :

    // DELETE THIS LINE: val v = inflater.inflate(R.layout.fragment_drivers, container, false)
    binding = FragmentDriversBinding.inflate(layoutInflater)
    // ...
    return binding.root

此外,在 onViewCreated() 中设置 View 比在 onCreateView() 中设置 View 更合适。如果这样做,您实际上可以通过将 View ID 传递给 Fragment 构造函数,将膨胀转移到 super 构造函数调用中,然后绑定(bind)到现有 View 而不是膨胀绑定(bind)。它看起来像这样:

class DriversFragment : Fragment(R.layout.fragment_drivers) {

    private lateinit var recyclerView: RecyclerView
    private lateinit var myAdapter: DriverFragmentAdapter;
    lateinit var binding: FragmentDriversBinding
    private val drivers = ArrayList<Drivers>()
    val url = "https://robcorp.net/f1api/getdrivers.php"

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = FragmentDriversBinding.bind(view)
        recyclerView = binding.driversRecyclerView

        recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)

        myAdapter = DriverFragmentAdapter(drivers)

        recyclerView.adapter = myAdapter
        println("adapter loaded")
        downloadDrivers()
    }

    //...
}

关于java - 为什么 RecyclerView 在其他 Kotlin Android 之前加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71992973/

相关文章:

kotlin - kotlin-native 有析构函数吗?

java - 为什么RecursiveTask在fork join中实现Serialized?

java - 将二维数组打印为文字 "array of arrays"(阅读说明)

android - 确定 Android 中的 Wi-Fi 可用性

android - 调用第二个Android Activity

kotlin 程序错误 : no main manifest attribute in jar file

android - 包含协程延迟时如何对协程进行单元测试?

java - 为什么 tomcat7.0.47 在将前端 Controller servlet 映射到 *.do 或/或/* 的 URL 模式时无法访问静态资源(js、css)

java - 用java poi解析公式不起作用

android - 重新加载 ViewPager 不会创建前 3 个 fragment