RecyclerView + LiveData, ViewModel, Firebase Realtime Database, DataBinding

Lee HyeongJong·2022년 8월 2일
0

안드로이드

목록 보기
10/43

1. Firebase설치 및 연동

안드로이드 스튜디오 Tool - FireBase를 클릭.

1과 2를 모두 진행 해야 한다.

일단 1 진행.

파이어베이스로 와서 프로젝트 생성.

이제 2를 진행한다.

마지막으로 안드로이드 스튜디오 build.gradel(app)파일에 firebase의 라이브러리를 추가해준다.

implementation platform('com.google.firebase:firebase-bom:30.2.0')
implementation 'com.google.firebase:firebase-database-ktx'
implementation 'com.google.firebase:firebase-analytics-ktx'

bom은 ktx에 들어가는 버전이다

2. RecyclerView + LiveData, ViewModel, Firebase Realtime Database, DataBinding 연동

Realtime Database 클릭 후 데이터베이스 만들기 클릭.

싱가포르가 가까우니 싱가포르로 하자.

테스트 모드와 잠금모드가 있다.
잠금모드는 사용법이 다르니 이부분은 뒤에서 다루도록 하자.

+버튼을 눌러 데이터를 추가해준다.

다음과 같은 모양으로 데이터를 넣어준다.

ViewModel과 LiveData를 gradle에 추가한다.

def lifecycle_version = "2.5.0"

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // ViewModel

implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" // LiveDat_a

다음과 같이 데이터 클래스를 만들어준다.

class CafeData(
    val cafeName : String = "CafeName",
    val cafeInsta : String = "CafeInsta",
    val cafeAddress : String = "CafeAddress",
    val latitude : Double = 0.0,
    val longitude : Double= 0.0,
    val cafeNumber : String = "CafeNumber",
    val cafeDescription : String = "CafeDescription",
    val score : Double = 0.0,
    val logoUrl : String = "LogoUrl",
) : Serializable {

}

리사이클러에 필요한 아답터를 만든다

data class ThisMonthListAdapter(
    val mContext : Context,
) : RecyclerView.Adapter<ThisMonthListAdapter.MyViewHolder>() {

    var mList = mutableListOf<CafeData>()

    var oic : OnItemClick? = null
    var oilc : OnItemLongClick? = null

    fun setListData(data:MutableList<CafeData>){
        mList = data
    }

    inner class MyViewHolder(val view : View) : RecyclerView.ViewHolder(view){

        val cafeName = view.findViewById<TextView>(R.id.txtItemCafeName) //카페이름
        val cafeAddress = view.findViewById<TextView>(R.id.txtItemCafeAddress) //카페주소
        val cafeDescription = view.findViewById<TextView>(R.id.txtItemCafeDescription) //카페설명
        val ratingBarCafeScore = view.findViewById<BaseRatingBar>(R.id.ratingBarCafeScore) //카페별점
        val imgCafeLogo = view.findViewById<ImageView>(R.id.imgCafeLogo) //카페로고

        fun bind(data : CafeData){

            cafeName.text = data.cafeName //카페이름
            cafeAddress.text = data.cafeAddress //카페주소
            cafeDescription.text = data.cafeDescription //카페설명
            ratingBarCafeScore.rating = data.score.toFloat() //카페별점
            Glide.with(mContext).load(data.logoUrl).into(imgCafeLogo) //카페로고

            if (oic != null) {
                view.setOnClickListener {
                    oic!!.onItemClick(position)
                }
            }

            if (oilc != null) {
                view.setOnLongClickListener {
                    oilc!!.onItemLongClick(position)
                    return@setOnLongClickListener true
                }
            }

        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {

        val view = LayoutInflater.from(mContext).inflate(R.layout.this_month_list_item, parent, false)
        return MyViewHolder(view)

    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
//        실제 출력할 데이터

        val data = mList[position]

//        MyViewHolder도 일종의 클래스 : 멤버변수 / 함수를 가지고 있을 수 있다. => 활용하자.
        holder.bind( data )

    }

    override fun getItemCount() = mList.size // 목록의 갯수가 리턴.
}

뷰모델과 해당 데이터를 끌어와 캡슐화를 진행할 Repository가 필요하다.

class ListViewModel : ViewModel() {

    private val repo = Repo()

    fun fetchData() : LiveData<MutableList<CafeData>> {

        val mutableData = MutableLiveData<MutableList<CafeData>>()

        repo.getData().observeForever {

            mutableData.value = it

        }
        return mutableData

    }
}

그리고 Repository는 테스트모드와 잠금모드에서 조금 차이가 있다.
테스트 모드 사용법

val mutableData = MutableLiveData<MutableList<CafeData>>()
val database = Firebase.database
val myRef = database.getReference("CafeData")

잠금모드는 하기와 같이 뒤에 주소를 추가한다.

val database = Firebase.database("https://~~~~~~.app/")

레포지토리

class Repo {

    fun getData() : LiveData<MutableList<CafeData>> {

        val mutableData = MutableLiveData<MutableList<CafeData>>()
        val database = Firebase.database("https://coffeezoo-30c55-default-rtdb.asia-southeast1.firebasedatabase.app/")
        val myRef = database.getReference("CafeData")

        myRef.addValueEventListener(object : ValueEventListener {

            val listData : MutableList<CafeData> = mutableListOf<CafeData>()

            override fun onDataChange(snapshot: DataSnapshot) {

                if (snapshot.exists()){

                    listData.clear() //실시간 데이터 업데이트 시 리사이클러뷰 데이터 중복 방지

                    for ( userSnapshot in snapshot.children ){

                        val getData = userSnapshot.getValue(CafeData::class.java)
                        listData.add(getData!!)

                        mutableData.value = listData

                    }

                }

            }

            override fun onCancelled(error: DatabaseError) {



            }


        })
        return mutableData

    }

}

그리고 리사이클러를 설치할 엑티비티 혹은 프래그먼트에 다음과 같이 작성한다.

class ThisMonthListFragment : BaseFragment() {

    lateinit var binding : FragmentThisMonthListBinding

    lateinit var mAdapter : ThisMonthListAdapter

    private val viewModel by lazy { ViewModelProvider(this).get(ListViewModel::class.java) }

아답터 연결

mAdapter = ThisMonthListAdapter(mContext)
//      리싸이클러뷰 연결
binding.thisMonthRecyclerView.adapter = mAdapter
//      리싸이클러뷰 모양설정
binding.thisMonthRecyclerView.layoutManager = LinearLayoutManager(mContext)

ViewModel에 연결 및 클릭이벤트

 fun observerData(){
//        fragment 에서 this 대신 viewLifecycleOwner 를 사용
        viewModel.fetchData().observe(viewLifecycleOwner, Observer {
            mAdapter.setListData(it)
            mAdapter.notifyDataSetChanged()

//            클릭이벤트
            mAdapter.oic = object : OnItemClick{
                override fun onItemClick(position: Int) {

                    val clickCafeStore = it[position]

                    val myIntent = Intent(mContext, CafeDetailViewActivity::class.java)
                    myIntent.putExtra("clickedCafeDetail", clickCafeStore)
                    startActivity(myIntent)

                }

            }

        })

    }
profile
코딩을 시작해보자

0개의 댓글