你好,我正在为我的家庭作业(job)做一个小应用程序,我想在这个应用程序上显示来self 的php api的数据.但Recycler视图在适配器代码运行之前发送此消息2022-04-25 00:41:36.662 13593-13593/net.robcorp.finalapp E/RecyclerView: No adapter attached; skipping layout,因为此消息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)]显示在前一条消息之后,并且假定在适配器之前运行.

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)
    }
}

Here is the 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()
    }

}

你的司机.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已经在布局中,它会在视图层次 struct 变得可见时try 绘制它,发现没有分配适配器,因此它只会发出警告,而不会绘制它.

也许创建适配器(带有一个空列表)并在视图inflating 时立即分配它,然后在数据准备就绪时更新它的列表会更干净.

顺便说一句,将布局放大到onCreate是不正确的.这应该在onCreateView年完成.


编辑:

这里的代码对布局进行了两次inflating ,一次用于变量v,一次用于binding属性.首先,没有理由再充气两次.其次,由于使用v作为onCreateView的返回值,所以对binding中的视图所做的任何操作都是毫无意义的,并且对屏幕上的视图没有任何影响.

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

您应该只对视图充气一次(使用绑定),然后返回绑定的视图:

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

此外,将视图设置为onViewCreated()比设置为onCreateView()更合适.如果这样做,实际上可以通过将视图ID传递给片段构造函数,将inflating 移到超级构造函数调用中,然后绑定到现有视图,而不是inflating 绑定.看起来是这样的:

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相关问答推荐

使用Apache Poi MQLSlideShow,在XSLFTable表中,我们可以在文本段落后面的每个单元格中包含圆角矩形吗?

为什么我的画布没有显示在PFA应用程序中?

无法在WebSocket onMessage中捕获错误

如何使用带有谓词参数的方法,而不使用lambda表达式

用户填充的数组列表永不结束循环

如何在antlr4中跳过所有反斜杠-换行符而保留换行符?

无法播放音频:从资源加载库GStreamer-Lite失败

Spring Boot中的应用程序.properties文件中未使用的属性

有谁能帮我修一下这个吗?使输出变得更加整洁

JFree Chart从图表中删除边框

向Java进程发送`kill-11`会引发NullPointerException吗?

处理4.3问题:javax.xml.ind包不存在(&Q;).您可能在学习GitHub教程时遗漏了库.&Q

我该如何为我的类编写getter和setter方法?

具有多个分析模式的复杂分隔字符串的正则表达式

ControlsFX RangeSlider在方向垂直时滞后

在JSON上获取反斜杠

java构造函数中的冻结操作何时发生?

睡眠在 Spring Boot 中

在java中使用SevenZip.openArchive方法后无法删除文件

setMaxTotal实际上是做什么的? (MySQL与Java和Apache BasicDataSource连接池)