使用 Kotlin 在 RecyclerView 上显示来自 Firestore 的数据

Display Data from Firestore on a RecyclerView using Kotlin

我正在尝试将集合中的数据放入 ArrayList 中,以便我可以在 RecycleView 上进一步显示它。

数据class如下:

data class Proyecto(
    val alcances :String,
    val alumnos :HashMap<String, Any>,
    val areasConoc :String,
    val asignaturas :String,
    val cliente :String,
    val colaboradores :String,
    val compDes :String,
    val compPrev :String,
    val coordinador: String,
    val departamentos  :String,
    val impacto :String,
    val institucion :String,
    val justificacion :String,
    val limityrest :String,
    val materiaEje :String,
    val periodo : HashMap<String, Any>,
    val plan :String,
    val planteamiento :String,
    val profeResp :String,
    val tipoejec :String,
    val tituloproyecto :String

)

我只需要将字段 tituloproyecto、coordinador 和 cliente 放入 recyclerview,所以这是我的 recyclerview 适配器:

class MyAdapter(私有 val 项目列表:ArrayList):RecyclerView.Adapter() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
    val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false)

    return MyViewHolder(itemView)
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    val proyecto : Proyecto = projectList[position]

    holder.tituloproyecto.text = proyecto.tituloproyecto
    holder.coordinador.text = proyecto.coordinador
    holder.cliente.text = proyecto.cliente
}

override fun getItemCount(): Int {

   return  projectList.size
}

public class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
    val tituloproyecto : TextView = itemView.findViewById(R.id.tv_titulo_rv)
    val coordinador: TextView = itemView.findViewById(R.id.tv_coordinador_rv)
    val cliente: TextView = itemView.findViewById(R.id.tv_cliente_rv)
}

}

这是将显示 recyclerview 的 Activity 的代码: class ProyectosAlumnoActivity : AppCompatActivity() {

private lateinit var recyclerView: RecyclerView
private lateinit var projectArrayList: ArrayList<Proyecto>
private lateinit var myAdapter: MyAdapter
private lateinit var db : FirebaseFirestore

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_proyectos_alumno)
    supportActionBar?.setTitle("Proyectos de Lorenzo")

    recyclerView = findViewById(R.id.recyclerView_al)
    recyclerView.layoutManager = LinearLayoutManager (this)
    recyclerView.setHasFixedSize(true)

    projectArrayList = arrayListOf()

    myAdapter = MyAdapter(projectArrayList)
    recyclerView.adapter = myAdapter

    EventChangeListener()
}

private fun EventChangeListener() {
    db = FirebaseFirestore.getInstance()

// db.collection("Proyecto").get().addOnSuccessListener { }

    db.collection("Proyecto")
        .addSnapshotListener(object : EventListener<QuerySnapshot>{
            override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
                if (error != null)
                {
                    Log.e("Firestore error", error.message.toString())
                    return
                }

                for (dc: DocumentChange in value?.documentChanges!!){
                    if (dc.type == DocumentChange.Type.ADDED){
                        projectArrayList.add(dc.document.toObject(Proyecto::class.java))
                    }
                }
                myAdapter.notifyDataSetChanged()

            }
    })


}

我收到以下错误消息:

2022-05-29 18:30:38.363 6252-6252/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.firebasecrudapplication, PID: 6252
    java.lang.RuntimeException: Could not deserialize object. Class com.example.firebasecrudapplication.models.Proyecto does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped
        at com.google.firebase.firestore.util.CustomClassMapper.deserializeError(CustomClassMapper.java:568)
        at com.google.firebase.firestore.util.CustomClassMapper.access0(CustomClassMapper.java:57)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:754)
        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:746)
        at com.google.firebase.firestore.util.CustomClassMapper.convertBean(CustomClassMapper.java:547)
        at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(CustomClassMapper.java:258)
        at com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:103)
        at com.google.firebase.firestore.DocumentSnapshot.toObject(DocumentSnapshot.java:183)
        at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(QueryDocumentSnapshot.java:116)
        at com.google.firebase.firestore.DocumentSnapshot.toObject(DocumentSnapshot.java:161)
        at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(QueryDocumentSnapshot.java:97)
        at com.example.firebasecrudapplication.ProyectosAlumnoActivity$EvenChangeListener.onEvent(ProyectosAlumnoActivity.kt:55)
        at com.example.firebasecrudapplication.ProyectosAlumnoActivity$EvenChangeListener.onEvent(ProyectosAlumnoActivity.kt:45)
        at com.google.firebase.firestore.Query.lambda$addSnapshotListenerInternal$com-google-firebase-firestore-Query(Query.java:1205)
        at com.google.firebase.firestore.Query$$ExternalSyntheticLambda2.onEvent(Unknown Source:6)
        at com.google.firebase.firestore.core.AsyncEventListener.lambda$onEvent[=14=]$com-google-firebase-firestore-core-AsyncEventListener(AsyncEventListener.java:42)
        at com.google.firebase.firestore.core.AsyncEventListener$$ExternalSyntheticLambda0.run(Unknown Source:6)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7842)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

让我相信这里的问题是 hashmap 字段没有被正确解析到数组列表中。

有什么办法可以解决这个问题吗?

您需要为模型字段提供默认值。如果文档快照中缺少特定字段,Firestore 会将默认值分配给该字段。

data class Proyecto(
    val alcances: String = "",
    val alumnos: HashMap<String, Any> = hashMapOf(),
    val areasConoc: String = "",
    val asignaturas: String = "",
    val cliente: String = "",
    val colaboradores: String = "",
    val compDes: String = "",
    val compPrev: String = "",
    val coordinador: String = "",
    val departamentos: String = "",
    val impacto: String = "",
    val institucion: String = "",
    val justificacion: String = "",
    val limityrest: String = "",
    val materiaEje: String = "",
    val periodo: HashMap<String, Any> = hashMapOf(),
    val plan: String = "",
    val planteamiento: String = "",
    val profeResp: String = "",
    val tipoejec: String = "",
    val tituloproyecto: String = ""
)

此外,建议使用Kotlin的不可变Map而不是Java的HashMap