전에 데이터를 불러와서 리사이클러뷰에 나타내는 글을 올린 적이 있다.
[안드로이드] 파이어베이스 파이어스토어의 데이터를 리사이클러뷰에 나타내기
여기에 한 번 검색 기능을 구현해 보았다. 위 글에서 만든 프로젝트에 이어서 진행할 것이므로 프로젝트 생성, 파이어스토어 연결의 과정은 생략하도록 하겠다.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:entries="@array/option" />
<EditText
android:id="@+id/searchWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="검색어를 입력해주세요."
android:inputType="text" />
<Button
android:id="@+id/searchBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="검색" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
activity_main.xml
이름을 검색할지 번호를 검색할지 옵션을 선택할 수 있는 방법을 찾다가 스피너를 통해 옵션 선택을 구현하기로 하였다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="option">
<item>이름</item>
<item>번호</item>
</string-array>
</resources>
array.xml
스피너에 들어갈 내용을 구현하기 위해 res-values에 array.xml을 생성해준다. item 태그 안에 들어갈 내용을 써주면 된다.
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:entries="@array/option" />
activity_main.xml
위와 같이 entries에 @array/array의 name을 넣어주면 된다.
검색어를 쓸 칸은 EditText으로, 검색 버튼은 Button으로 구현하였다.
일단 스피너에 기능을 넣어주도록 하자.
// 검색 옵션 변수
var searchOption = "name"
// 스피너 옵션에 따른 동작
spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (spinner.getItemAtPosition(position)) {
"이름" -> {
searchOption = "name"
}
"번호" -> {
searchOption = "phoneNumber"
}
}
}
}
MainActivity.kt
검색 옵션 변수를 만들어주고 스피너가 선택한 항목에 따라 검색 옵션이 달라지도록 하였다.
검색 기능을 구현할 땐 주로 LIKE절을 사용하였으나, 파이어스토어에서는 안타깝게도 LIKE절을 쓰지 못한다. 그러던 중 String 클래스의 contains 메소드를 사용하기로 하였다.
위는 C#에 대한 문서지만 자바의 contains 메소드도 이와 똑같은 기능을 가지고 있고 설명이 더 잘 되어있다고 생각해 가져왔다. 자바의 contains 메소드를 볼려면 왼쪽 링크를 클릭하면 된다.
// 파이어스토어에서 데이터를 불러와서 검색어가 있는지 판단
fun search(serachWord : String, option : String) {
firestore?.collection("telephoneBook")?.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
// ArrayList 비워줌
telephoneBook.clear()
for (snapshot in querySnapshot!!.documents) {
if (snapshot.getString(option)!!.contains(serachWord)) {
var item = snapshot.toObject(Person::class.java)
telephoneBook.add(item!!)
}
}
notifyDataSetChanged()
}
}
MainActivity.kt
이를 이용해서 검색 함수를 짜보았다. 검색 옵션(name or phoneNumber)에 따라 해당 필드에 검색어(searchWord)가 있을 시 데이터를 불러와 item의 형태로 저장해 리사이클러뷰에 추가해주는 형태이다.
// 검색 옵션에 따라 검색
searchBtn.setOnClickListener {
(recyclerview.adapter as RecyclerViewAdapter).search(searchWord.text.toString(), searchOption)
}
MainActivity.kt
이제 앞서 activity_main.xml에 추가한 버튼에 해당 함수를 실행할 수 있도록 OnClickListener를 추가해주면 된다.
package com.example.samplerecyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.item.view.*
class MainActivity : AppCompatActivity() {
var firestore : FirebaseFirestore? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 파이어스토어 인스턴스 초기화
firestore = FirebaseFirestore.getInstance()
recyclerview.adapter = RecyclerViewAdapter()
recyclerview.layoutManager = LinearLayoutManager(this)
// 검색 옵션 변수
var searchOption = "name"
// 스피너 옵션에 따른 동작
spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (spinner.getItemAtPosition(position)) {
"이름" -> {
searchOption = "name"
}
"번호" -> {
searchOption = "phoneNumber"
}
}
}
}
// 검색 옵션에 따라 검색
searchBtn.setOnClickListener {
(recyclerview.adapter as RecyclerViewAdapter).search(searchWord.text.toString(), searchOption)
}
}
inner class RecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
// Person 클래스 ArrayList 생성성
var telephoneBook : ArrayList<Person> = arrayListOf()
init { // telephoneBook의 문서를 불러온 뒤 Person으로 변환해 ArrayList에 담음
firestore?.collection("telephoneBook")?.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
// ArrayList 비워줌
telephoneBook.clear()
for (snapshot in querySnapshot!!.documents) {
var item = snapshot.toObject(Person::class.java)
telephoneBook.add(item!!)
}
notifyDataSetChanged()
}
}
// xml파일을 inflate하여 ViewHolder를 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
var view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ViewHolder(view)
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
}
// onCreateViewHolder에서 만든 view와 실제 데이터를 연결
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
var viewHolder = (holder as ViewHolder).itemView
viewHolder.name.text = telephoneBook[position].name
viewHolder.phoneNumber.text = telephoneBook[position].phoneNumber
}
// 리사이클러뷰의 아이템 총 개수 반환
override fun getItemCount(): Int {
return telephoneBook.size
}
// 파이어스토어에서 데이터를 불러와서 검색어가 있는지 판단
fun search(searchWord : String, option : String) {
firestore?.collection("telephoneBook")?.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
// ArrayList 비워줌
telephoneBook.clear()
for (snapshot in querySnapshot!!.documents) {
if (snapshot.getString(option)!!.contains(searchWord)) {
var item = snapshot.toObject(Person::class.java)
telephoneBook.add(item!!)
}
}
notifyDataSetChanged()
}
}
}
}
MainActivity.kt
전체 코드는 다음과 같다.
실행을 해보면 다음과 같이 정상적으로 작동한다.
Microsoft docs, "String.Contains 메서드 (System)", https://docs.microsoft.com/ko-kr/dotnet/api/system.string.contains?view=netcore-3.1
자바에 대한 글은 아니지만 동일한 기능을 수행하므로 가지고 왔다.
잘 봤습니다.