NullPointerException:尝试调用虚拟方法和 RecyclerView:没有附加适配器;从 Firestore 获取数据时跳过布局、错误

NullPointerException: Attempt to invoke virtual method & RecyclerView: No adapter attached; skipping layout, errors, when fetching data from Firestore

我试图从 Firestore 中获取数据并将其显示在 RecyclerView 中。但是,我收到以下错误。 我没有太多编码经验,但我尝试在我的项目中添加 RecyclerViewfragments

我正在使用 Kotlin 作为语言。

这三天我一直在想办法找出问题所在和解决方案,但现在我想我必须寻求像你这样的专家的帮助。

以下是我在Logcat

中得到的错误
16273-16273/com.example.quiz E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.quiz, PID: 16273
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.quiz/com.example.quiz.ui.activities.DashboardActivity}: android.view.InflateException: Binary XML file line #32 in com.example.quiz:layout/activity_dashboard: Binary XML file line #32 in com.example.quiz:layout/activity_dashboard: Error inflating class fragment
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3792)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3968)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8512)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
     Caused by: android.view.InflateException: Binary XML file line #32 in com.example.quiz:layout/activity_dashboard: Binary XML file line #32 in com.example.quiz:layout/activity_dashboard: Error inflating class fragment
     Caused by: android.view.InflateException: Binary XML file line #32 in com.example.quiz:layout/activity_dashboard: Error inflating class fragment
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object reference
        at com.example.quiz.ui.fragments.DashboardFragment.onCreateView(DashboardFragment.kt:28)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
        at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:392)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
        at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:140)
        at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
        at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)
        at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)
        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:699)
2021-05-27 07:25:09.097 16273-16273/com.example.quiz E/AndroidRuntime:     at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)
        at com.example.quiz.ui.activities.DashboardActivity.onCreate(DashboardActivity.kt:15)
        at android.app.Activity.performCreate(Activity.java:8198)
        at android.app.Activity.performCreate(Activity.java:8182)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3765)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3968)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8512)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
2021-05-27 07:25:09.166 16273-16273/com.example.quiz I/Process: Sending signal. PID: 16273 SIG: 9

Quiz.kt 文件

package com.example.quiz.models

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
data class Quiz(
    val user_id: String = "",
    var quiz_id: String = "",
    val quiz_name: String = "",
    val num_participants: String = "",
    val num_questions: String = "",
    val duration: String = ""

) : Parcelable

DashboardActivity.kt

package com.example.quiz.ui.activities

import android.os.Bundle
import androidx.core.content.ContextCompat
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.example.quiz.R

class DashboardActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_dashboard)
        
        supportActionBar!!.setBackgroundDrawable(
            ContextCompat.getDrawable(
                this@DashboardActivity,
                R.drawable.app_gradient_color_background
            )
        )

        val navView: BottomNavigationView = findViewById(R.id.nav_view)

        val navController = findNavController(R.id.nav_host_fragment)
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_quizzes,
                R.id.navigation_dashboard
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)

        navView.setupWithNavController(navController)
    }

    override fun onBackPressed() {
        doubleBackToExit()
    }
}

DashboardItemListAdapter.kt

package com.example.quiz.ui.adapters

import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.quiz.R
import com.example.quiz.models.Quiz
import kotlinx.android.synthetic.main.item_list_layout.view.*


open class DashboardItemsListAdapter(
    private val context: Context,
    private var list: ArrayList<Quiz>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {


    private var onClickListener: OnClickListener? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return MyViewHolder(
            LayoutInflater.from(context).inflate(
                R.layout.item_dashboard_layout,
                parent,
                false
            )
        )
    }


    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val model = list[position]

        if (holder is MyViewHolder) {

            holder.itemView.tv_quiz_name.text = model.quiz_name
            holder.itemView.tv_participants.text = model.num_participants
            holder.itemView.tv_questions.text = model.num_questions
            holder.itemView.tv_duration.text = model.duration

            holder.itemView.setOnClickListener {
                if (onClickListener != null) {
                    onClickListener!!.onClick(position, model)
                }
            }
        }
    }

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


    fun setOnClickListener(onClickListener: OnClickListener) {
        this.onClickListener = onClickListener
    }


    interface OnClickListener {

        fun onClick(position: Int, product: Quiz)
    }


    class MyViewHolder(view: View) : RecyclerView.ViewHolder(view)
}

QuizListAdapter.kt

package com.example.quiz.ui.adapters

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.quiz.R
import com.example.quiz.models.Quiz
//import com.example.Quiz.utils.GlideLoader
import kotlinx.android.synthetic.main.item_list_layout.view.*

open class QuizListAdapter(
    private val context: Context,
    private val list: ArrayList<Quiz>,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return MyViewHolder(
            LayoutInflater.from(context).inflate(
                R.layout.item_list_layout,
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        val model = list[position]

        if (holder is MyViewHolder) {

            holder.itemView.tv_quiz_name.text = model.quiz_name
            holder.itemView.tv_participants.text = model.num_participants
            holder.itemView.tv_questions.text = model.num_questions
            holder.itemView.tv_duration.text = model.duration

        }

    }

    override fun getItemCount(): Int {

        return list.size
    }

    class MyViewHolder(view: View) : RecyclerView.ViewHolder(view)
}

DashboardFragment.kt

package com.example.quiz.ui.fragments

import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.recyclerview.widget.GridLayoutManager
import com.example.quiz.R
import com.example.quiz.firestore.FirestoreClass
import com.example.quiz.models.Quiz
import com.example.quiz.ui.adapters.DashboardItemsListAdapter
import kotlinx.android.synthetic.main.fragment_dashboard.*

class DashboardFragment : BaseFragment() {

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

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        return inflater.inflate(R.layout.fragment_dashboard, container, false)
    }

    override fun onResume() {
        super.onResume()

        getDashboardItemsList()
    }

    private fun getDashboardItemsList() {
        showProgressDialog("please_wait")

        FirestoreClass().getDashboardItemsList(this@DashboardFragment)
    }

    fun successDashboardItemsList(dashboardItemsList: ArrayList<Quiz>) {

        hideProgressDialog()

        for (i in dashboardItemsList) {
            Log.i("Item Title", i.quiz_name)
        }

        if (dashboardItemsList.size > 0) {

            rv_dashboard_items.visibility = View.VISIBLE
            tv_no_dashboard_items_found.visibility = View.GONE

            rv_dashboard_items.layoutManager = GridLayoutManager(activity, 1)
            rv_dashboard_items.setHasFixedSize(true)

            val adapter = DashboardItemsListAdapter(requireActivity(), dashboardItemsList)
            rv_dashboard_items.adapter = adapter

        } else {
            rv_dashboard_items.visibility = View.GONE
            tv_no_dashboard_items_found.visibility = View.VISIBLE
        }
    }
}

使用上面的代码,我的应用程序在登录输入用户名和密码后崩溃,但是当我删除 rv_dashboard_items.adapter = adapter 至少应用程序不会崩溃。但是,它根本不显示来自 Firestore 的任何数据。

当我 运行 没有 rv_dashboard_items.adapter = adapter

的应用程序时,出现以下错误

以下代码段中的消息为红色。

E/DashboardFragment: [DocumentSnapshot{key=quizzes/C8STnkYwp3cYWMxm1Y0xQWERTZq1, metadata=SnapshotMetadata{hasPendingWrites=false, isFromCache=false}, doc=Document{key=quizzes/C8STnkYwp3cYWMxm1Y0xQWERTZq1, version=SnapshotVersion(seconds=1621955183, nanos=678854000), type=FOUND_DOCUMENT, documentState=SYNCED, value=ObjectValue{internalValue=# com.google.firestore.v1.Value@1abc2d14
integer_value: 0
map_value {
  fields {
    key: "quiz_id"
    value {
      integer_value: 0
      string_value: "C8STnkYwp3cYWMxm1Y0xQWERTZq1"
    }
  }
  fields {
    key: "num_questions"
    value {
      integer_value: 0
      string_value: "10"
    }
  }
  fields {
    key: "quiz_name"
    value {
      integer_value: 0
      string_value: "Easy Quiz"
    }
  }
  fields {
    key: "duration"
    value {
      integer_value: 0
      string_value: "10"
    }
  }
  fields {
    key: "num_participants"
    value {
      integer_value: 0
      string_value: "5"
    }
  }
  fields {
    key: "user_id"
    value {
      integer_value: 0
      string_value: "C8STnkYwp3cYWMxm1Y0xQWERTZq1"
    }
  }
}}}}]

还有这一行

E/RecyclerView: No adapter attached; skipping layout

QuizFragment.kt

package com.example.quiz.ui.fragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.quiz.R
import com.example.quiz.firestore.FirestoreClass
import com.example.quiz.models.Quiz
import com.example.quiz.ui.adapters.QuizListAdapter
import kotlinx.android.synthetic.main.fragment_quiz.*

class QuizFragment : BaseFragment() {

    private lateinit var mRootView: View


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mRootView = inflater.inflate(R.layout.fragment_quiz, container, false)
        return mRootView
    }

    fun successQuizListFromFireStore(quizList: ArrayList<Quiz>) {

        hideProgressDialog()

        if (quizList.size > 0) {
            rvQuizzesFrag.visibility = View.VISIBLE
            tv_no_products_found.visibility = View.GONE

            rvQuizzesFrag.layoutManager = LinearLayoutManager(activity)
            rvQuizzesFrag.setHasFixedSize(true)
            val adapterQuizzes = QuizListAdapter(requireActivity(), quizList)
            rvQuizzesFrag.adapter = adapterQuizzes

        } else {
            rvQuizzesFrag.visibility = View.GONE
            tv_no_products_found.visibility = View.VISIBLE
        }
    }


    private fun getQuizListFromFireStore() {

        showProgressDialog("Please_wait")
        FirestoreClass().getQuizList(this)
    }

    override fun onResume() {
        super.onResume()
        getQuizListFromFireStore()
    }
}

activity_dashboard.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"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="@drawable/app_gradient_color_background"
        app:itemIconTint="@color/colorWhite"
        app:itemTextColor="@color/colorWhite"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />


</androidx.constraintlayout.widget.ConstraintLayout>

fragment_dashboard.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"
    android:background="@color/white"
    tools:context=".ui.fragments.DashboardFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_dashboard_items"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_no_dashboard_items_found"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="no_dashboard_item_found"
        android:textAlignment="center"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

fragment_quiz.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=".ui.fragments.QuizFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvQuizzesFrag"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_no_products_found"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="NO QUIZZES TODAY"
        android:textAlignment="center"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

FirestoreClass.kt

Import 部分代码已从问题中删除,因为我超出了问题中的字符限制。

package com.example.quiz.firestore


class FirestoreClass {

    private val mFireStore = FirebaseFirestore.getInstance()

    fun getDashboardItemsList(fragment: DashboardFragment) {
       
        mFireStore.collection("quizzes")
            .get() 
            .addOnSuccessListener { document ->

                Log.e(fragment.javaClass.simpleName, document.documents.toString())

                val quizList: ArrayList<Quiz> = ArrayList()

               
                for (i in document.documents) {

                    val qz = i.toObject(Quiz::class.java)!!
                    qz.quiz_id = i.id
                    quizList.add(qz)
                }

                fragment.successDashboardItemsList(quizList)
            }
            .addOnFailureListener { e ->
              
                fragment.hideProgressDialog()
                Log.e(fragment.javaClass.simpleName, "Error while getting dashboard items list.", e)
            }
    }


    fun getCurrentUserID(): String {
        // An Instance of currentUser using FirebaseAuth
        val currentUser = FirebaseAuth.getInstance().currentUser

        var currentUserID = ""
        if (currentUser != null) {
            currentUserID = currentUser.uid
        }

        return currentUserID
    }


    fun uploadProductDetails(activity: AddProductActivity, productInfo: Quiz) {

        mFireStore.collection("quizzes")
            .document()
          
            .set(productInfo, SetOptions.merge())
            .addOnSuccessListener {

              
                activity.productUploadSuccess()
            }
            .addOnFailureListener { e ->

                activity.hideProgressDialog()

                Log.e(
                    activity.javaClass.simpleName,
                    "Error while uploading the product details.",
                    e
                )
            }
    }

    fun getUserDetails(activity: Activity) {

        mFireStore.collection("users")
         
            .document(getCurrentUserID())
            .get()
            .addOnSuccessListener { document ->

                Log.i(activity.javaClass.simpleName, document.toString())

                val user = document.toObject(User::class.java)!!

                val sharedPreferences =
                    activity.getSharedPreferences(
                        Constants.MYAPP_PREFERENCES,
                        Context.MODE_PRIVATE
                    )

                val editor: SharedPreferences.Editor = sharedPreferences.edit()
                editor.putString(
                    Constants.LOGGED_IN_USERNAME,
                    "${user.firstName} ${user.lastName}"
                )
                editor.apply()

                when (activity) {
                    is LoginActivity -> {
                      
                        activity.userLoggedInSuccess(user)
                    }

                }
            }
            .addOnFailureListener { e ->
               
                when (activity) {
                    is LoginActivity -> {
                        activity.hideProgressDialog()
                    }
                }

                Log.e(
                    activity.javaClass.simpleName,
                    "Error while getting user details.",
                    e
                )
            }
    }


    fun getQuizList(fragment: Fragment) {
      
        mFireStore.collection("quizzes")
            .whereEqualTo("user_id", getCurrentUserID())
            .get() 
            .addOnSuccessListener { document ->

                Log.e("Products List", document.documents.toString())

                val productsList: ArrayList<Quiz> = ArrayList()

                for (i in document.documents) {

                    val product = i.toObject(Quiz::class.java)
                    product!!.quiz_id = i.id

                    productsList.add(product)
                }

                when (fragment) {
                    is QuizFragment -> {
                        fragment.successQuizListFromFireStore(productsList)
                    }
                }
            }
            .addOnFailureListener { e ->
               
                when (fragment) {
                    is QuizFragment -> {
                        fragment.hideProgressDialog()
                    }
                }

                Log.e("Get Product List", "Error while getting product list.", e)
            }
    }


    fun getAllQuizList(activity: Activity) {
       
        mFireStore.collection("quizzes")
            .get() 
            .addOnSuccessListener { document ->

                Log.e("Products List", document.documents.toString())

                val productsList: ArrayList<Quiz> = ArrayList()

                for (i in document.documents) {

                    val product = i.toObject(Quiz::class.java)
                    product!!.quiz_id = i.id

                    productsList.add(product)
                }

            }
            .addOnFailureListener { e ->
                Log.e("Get Product List", "Error while getting all product list.", e)
            }
    }

}

看了你的代码,我觉得原因是:你的recycleView.

的使用可能有一些小问题

在你的代码中,你似乎在xml的同一个地方使用了两个recycleView,一个是没有数据的recycleView,另一个是recycleView 异步获取数据后。然后在获取数据的函数中控制recycleView的显示和隐藏?

但是,如果在将 recyclerview 附加到 Fragment 后不立即对其进行初始化,您可能会看到 No adapter attached; skipping layout

解决方法:设置一个recycleView,在Fragment/activity的初始化函数中设置一个空数据给它。 DashboardItemsListAdapter(requireActivity(), listOf<Quiz>())

部分代码:


private lateinit var adapter: DashboardItemsListAdapter

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    adapter = DashboardItemsListAdapter(requestActivity(), arrayListOf<Quiz>())
}

fun successDashboardItemsList(dashboardItemsList: ArrayList<Quiz>) {
    adapter.list = dashboardItemsList
    adapter.notifyDataSetChanged()
}



我只是在这里提供我的一个想法。您不能在每次调用 successDashboardItemsList() 时都设置新的适配器。在调用 successDashboardItemsList() 之前,您的适配器应该被初始化(可能没有数据)。每次调用 successDashboardItemsList() 时, 重新分配 Adapter 对象的列表字段的值。并调用Adapter对象的notifyDataSetChanged(),这样问题就解决了


import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.recyclerview.widget.GridLayoutManager
import com.example.quiz.R
import com.example.quiz.firestore.FirestoreClass
import com.example.quiz.models.Quiz
import com.example.quiz.ui.adapters.DashboardItemsListAdapter
import kotlinx.android.synthetic.main.fragment_dashboard.*

class DashboardFragment : BaseFragment() {

    private lateinit var adapter: DashboardItemsListAdapter

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

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_dashboard, container, false)
    }



    private lateinit var recyclerView: RecyclerView

    private lateinit var textView: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerView = view.findViewById<RecyclerView>(R.id.rv_dashboard_items)
        textView = view.findViewById(R.id.tv_no_dashboard_items_found)
        adapter = DashboardItemsListAdapter(requireActivity(), arrayListOf<Quiz>())
        recyclerView.layoutManager = GridLayoutManager(requireContext(), 1)
        recyclerView.setHasFixedSize(true)
        recyclerView.adapter = adapter
    }

    override fun onResume() {
        super.onResume()

        getDashboardItemsList()
    }

    private fun getDashboardItemsList() {
        showProgressDialog("please_wait")

        FirestoreClass().getDashboardItemsList(this@DashboardFragment)
    }

    fun successDashboardItemsList(dashboardItemsList: ArrayList<Quiz>) {

        hideProgressDialog()

        for (i in dashboardItemsList) {
            Log.i("Item Title", i.quiz_name)
        }

        if (dashboardItemsList.size > 0) {

            recyclerView.visibility = View.VISIBLE
            textView.visibility = View.GONE

            adapter.list = dashboardItemsList
            adapter.notifyDataSetChanged()
        } else {
            recyclerView.visibility = View.GONE
            textView.visibility = View.VISIBLE
        }
    }
}

DashboardItemListAdapter.kt

变为:

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
         return MyViewHolder(
             LayoutInflater.from(context).inflate(
                 R.layout.item_list_layout,
                 parent,
                 false
             )
         )
     }

在您的 DashboardItemsListAdapter 中,您正在膨胀 item_dashboard_layout 但您正在为 fragment_dashboard.

导入合成绑定

膨胀的布局可能不包含 fragment_dashboard 绑定所需的视图,因此绑定 returns 为空值。

确保您对膨胀和视图绑定使用相同的布局。