在Android中实现Firebase数据库的自定义搜索和过滤
Firebase实时数据库是一个NoSQL数据库,它允许我们在用户之间实时存储和同步数据。这是一个大型的JSON对象,开发者可以使用单个API进行实时管理。
查询指令简化了对MySQL和SQLite等关系型数据库中不同属性数据的过滤和搜索。然而,在Firebase实时数据库中,即使进行简单的数据查询,过滤和搜索也会相对复杂。
前提条件
要跟上本教程,你应该。
- 对Kotlin编程语言有一个基本的掌握。
- 理解Android开发的基本原理。
- 熟悉如何将你的项目连接到Firebase。
目标
本文打算指导和帮助读者充分理解Firebase实时数据库中的搜索和过滤,以及使这个过程成功的所有实现和方法。
Firebase实时数据库是如何结构化的
在大多数数据库中,数据都是以表和行来组织的。然而,Firebase实时数据库是一个NoSQL数据库,它以JSON格式组织数据,这些数据被安排在一个叫做集合的树状结构中。
为了创建这种树状结构,被称为节点的元素被两个相连的节点共享的一般路径连接起来。
如下图所示,一个子节点可以嵌套在连接的节点中,形成一个广泛的嵌套结构。

Firebase实时数据库的优势
- 能够通过单一路径访问数据库中的数据。
- 在Firebase中创建数据格式很简单,因为你可以使用一个自动生成的ID或者定义你自己的。
- 一个单一的子路径列出了存储数据里面的所有变化。
- 它是一个NoSQL数据库,这意味着它不限于关系型数据库。
Firebase实时数据库的劣势
- 寻找某个项目是很困难的,因为没有查询语言可以使用。
- 删除一个特定的子项目很困难,因为它需要在所有的数据中寻找要删除的项目的位置。
在Firebase实时数据库中过滤和搜索数据的方法
尽管在Firebase数据库中搜索数据很困难,但还是有各种技术来搜索和过滤数据。
这些标准是:。
- 通过使用
id,这通常是用来寻找一个特定的值,该值有其id。 - 通过使用一个子路径,从中列出数据库中数据的任何变化。
- 通过使用一个可以作为参数的变量。
- 采用过滤技术,如
orderByChild。
用于过滤数据的方法
有几种方法有助于对Firebase数据进行过滤和排序。为了进行排序,我们使用了下面的方法。
orderByChild- 该方法根据指定的子集合或子路径对数据进行排序。orderByKey- 根据指定的键值执行排序。orderByValue- 根据给定的子值对数据进行排序。
另外,过滤是由以下方法处理的。
limitToFirst-从给定的参数值开始过滤数据。limitToLast- 将数据限制在最后提供的值。startAt- 从提供的键或值开始过滤数据。startAfter- 在给定的键或值之后过滤。equalTo过滤某一个键或值类别的数据。endAt- 将数据限制在提供的键或值上。endBefore- 准确地在指定的值之前过滤数据。
让我们开始吧 :)
第1步:创建一个空项目
启动Android Studio并创建一个空的活动项目,从头开始一个新项目。接下来,给你的项目一个描述性的名字。

第2步:将你的项目链接到Firebase
为了获得对Firebase数据库的访问,你的项目必须连接到Firebase,这可以通过以下方式完成。
在你的浏览器上,搜索Firebase控制台,进入Add project -> 输入项目名称 -> 选择Firebase的默认账户 -> 创建项目。
确保你已经启用了Realtime数据库。
第3步:设计用户界面
在这一步,我们将创建一个简单的布局,这将有助于以列表的方式显示数据。例如,我们将有一个EditText ,以输入一个搜索词。另外,该布局将有两个按钮:一个用于过滤数据,另一个用于搜索。
注意:你必须创建一个行的布局,映射出你的数据将如何出现在RecyclerView中。
用户界面应该如下图所示。

第4步:创建模型类和适配器类
模型类是用来映射Firebase中的数据,并为这些数据建立一个访问点。下面的代码演示了如何创建一个模型类。
data class Students(
val id:String? = "",
val name: String? = "",
val regno: String? = "",
val gender:String? = "",
val amount: Int? = 0,
val age:Int?= 0
)
适配器类作为访问数据和RecyclerViews之间的链接。下面的代码演示了如何创建一个适配器类。
class StudentsAdapter: ListAdapter<Students, StudentsAdapter.MyHolder>(COMPARATOR) {
// Calculates the difference between the available data and new data
private object COMPARATOR: DiffUtil.ItemCallback<Students>(){
override fun areItemsTheSame(oldItem: Students, newItem: Students): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Students, newItem: Students): Boolean {
return oldItem.id == newItem.id
}
}
// An inner class that maps data with the available views
inner class MyHolder(private val binding: StudentsRowBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(student: Students?) {
binding.tvName.text = student?.name
binding.tvRegNumber.text = student?.regno
binding.tvAmount.text = student?.amount.toString()
binding.tvAge.text = student?.age.toString()
binding.tvGender.text = student?.gender.toString()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
return MyHolder(StudentsRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}
override fun onBindViewHolder(holder: MyHolder, position: Int) {
val student = getItem(position)
holder.bind(student)
}
}
第5步:显示Firebase的数据
在执行任何搜索或过滤操作之前,首先显示来自Firebase的数据是至关重要的。
首先,创建一个DatabaseReference 的实例。
private lateinit var databaseReference: DatabaseReference
在你的onCreate ,确保你已经初始化了databaseReference 。
databaseReference = FirebaseDatabase.getInstance().getReference("students")
定义以下方法并在你的onCreate 方法中调用它来获取数据。
// fetching all values from firebase
private fun getStudents() {
databaseReference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (i in snapshot.children) {
val student = i.getValue(Students::class.java)
if (student != null) {
studentsList.add(student)
}
}
studentAdapter.submitList(studentsList)
binding.recyclerStudents.adapter = studentAdapter
} else {
Toast.makeText(applicationContext, "Data Does not Exist", Toast.LENGTH_SHORT).show()
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
第6步:实现过滤
过滤可以通过两种方式完成。
- 传递过滤参数或
- 使用数据中的一个普通值,比如说性别。
要使用一个标准的类别进行过滤,我们可以定义这样一个函数。
// filtering in general
private fun filterGender(){
// Specifying path and filter category and adding a listener
databaseReference.orderByChild("gender").equalTo("female").addValueEventListener(object:ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if(snapshot.exists()){
studentsList.clear()
for (i in snapshot.children){
val female = i.getValue(Students::class.java)
studentsList.add(female!!)
}
studentAdapter.submitList(studentsList)
binding.recyclerStudents.adapter = studentAdapter
} else{
Toast.makeText(applicationContext, "Data is not found", Toast.LENGTH_SHORT).show()
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
要使用RecyclerView中显示的列表中的一个特定参数进行过滤。我们可以通过首先定义一个名为filter 的方法进行搜索。
private fun filter(e: String) {
//Declare the array list that holds the filtered values
val filteredItem = ArrayList<Students>()
// loop through the array list to obtain the required value
for (item in studentsList) {
if (item.name!!.toLowerCase().contains(e.toLowerCase())) {
filteredItem.add(item)
}
}
// add the filtered value to adapter
studentAdapter.submitList(filteredItem)
}
之后,我们可以在一个TextWatcher 里面调用这个函数,这个函数会监听在EditText 中输入的每一个字符。然后会在列表中循环,看是否可以找到输入的字符。
binding.etSearch.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun afterTextChanged(editable: Editable?) {
filter(editable.toString())
}
})
第7步:实现搜索
人们可以根据某个值来搜索数据,比如说名字。这可以通过定义一个方法来实现,该方法接收搜索条件并从Firebase中执行搜索。
private fun searchByName(name: String) {
// adding a value listener to database reference to perform search
databaseReference.addValueEventListener(object:ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
// Checking if the value exists
if (snapshot.exists()){
studentsList.clear()
// looping through the values
for (i in snapshot.children){
val student = i.getValue(Students::class.java)
// checking if the name searched is available and adding it to the array list
if (student!!.name == name){
studentsList.add(student)
}
}
//setting data to RecyclerView
studentAdapter.submitList(studentsList)
binding.recyclerStudents.adapter = studentAdapter
} else{
Toast.makeText(applicationContext, "Data does not exist", Toast.LENGTH_SHORT).show()
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
当你运行这个应用程序时,你应该得到以下输出。

结论
在本教程中,我们已经讨论了Firebase实时数据库是如何构建其数据的,我们执行搜索和过滤的不同方式,过滤数据时使用的方法,以及最后在Android中实现搜索和过滤。