使用 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
。
我正在尝试将集合中的数据放入 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
。