Android/Kotlin

[Android/Kotlin] 데이터 바인딩(DataBinding)

__JeongYeon 2022. 7. 15. 15:16
반응형

[모든 포스팅은 개인적 공부를 위해 작성된 글입니다]

<데이터 바인딩(DataBinding)>

- Android JetPack 라이브러리 중 하나

- xml에 데이터 연결하는 작업

- findViewById() 사용하지 않아도 됨

 - 자동으로 xml에서 만든 View들을 만들어 줌

- MVVM 패턴, LiveData와 함께 사용(필수인 것은x)

- Observable 사용해 실시간으로 데이터 변경 가능

- RecyclerView 내부 아이템을 set하지 않아도 xml에서 자동으로 처리

- 간결한 코드 작성 가능

 

<데이터 바인딩으로 버튼에 클릭 리스너 적용하기>

- gradle app 수준

apply plugin: 'kotlin-kapt'
android {
    dataBinding{
        enabled = true
    }
}
dependencies {
	kapt 'com.android.databinding:compiler:3.1.4'//맨 마지막 숫자 == gradle 버전
}

*Java의 경우 dataBinding{enabled=true}만 해주면 됨*

 

- xml 준비

<?xml version="1.0" encoding="utf-8"?>
<layout 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"
    tools:context=".DataBinding_Activity">
    <data>
        <variable
            name="activity"
            type="org.j_______jy.techtown.DataBinding_Activity" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼"
            android:onClick="@{activity::buttonClick}"/>        
    </LinearLayout>
</layout>

 - <layout> 태그를 최상위에 붙여줌

  - 최상위 태그를 layout으로 바꾸고 layout_width, layout_height를 지워주지 않은 바람에 오류가 발생했다.. 나 같은 실수를 하지 않게 조심하자ㅜㅜ

 - <data> 태그 내부

 - name은 변수 이름을 의미하고 type은 해당 클래스의 경로 의미

  - 처음에 name을 databinding_activity로 했더니 오류 남(_을 쓰면 안되는건지 내가 놓치고 있는 무언가가 있는 것인지 의문..)

 - DataBinding_Activity.kt 파일

class DataBinding_Activity : AppCompatActivity() {
    private lateinit var binding: ActivityDataBindingBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding)
        binding.activity = this@DataBinding_Activity
    }

    fun buttonClick(view: View){
        Log.d("click","클릭")
    }
}

 - ActivityDataBindingBinding : xml 파일명인 activity_data_binding.xml이 파스칼 표기법으로 바뀐 것

 - setContentView 부분을 위와 같이 변경

 - 기존의 버튼에 직접 리스너 달아주었던 것과 달리 클릭 시 호출 할 함수(buttonClick)만 선언

 - 반드시 click 함수의 파라미터로 View를 전달해줘야 함

 - 프로젝트 새로 생성했다가 binding.activity = this를 깜빡해 한참 헤맸다.. 다음에는 이런 실수 하지 않게 조심하자..(정말 바보 같은 행동이었다...........)

 

 - Fragment에서 사용하는 경우

lateinit var binding: FragmentLoginBinding

  - onCreateView 내부

binding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
binding.loginFragment = this@LoginFragment
return binding.root

 

<RecyclerView에서 데이터 바인딩 사용하기>

 - xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="recyclerview"
            type="org.j_______jy.domain.item.ToDo" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/title_textView"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="9"
            android:text="@{recyclerview.title}"/>
        <Button
            android:id="@+id/delete_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

</layout>

 - Adapter 클래스

package org.j_______jy.todo_is.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.j_______jy.domain.item.ToDo
import org.j_______jy.todo_is.databinding.ActivityMainBinding
import org.j_______jy.todo_is.databinding.TodoRecyclerviewBinding

class ToDo_RecyclerView_Adapter(private val context: Context): RecyclerView.Adapter<ToDo_RecyclerView_Adapter.ViewHolder>() {
    var data = listOf<ToDo>()

    class ViewHolder(val binding: TodoRecyclerviewBinding): RecyclerView.ViewHolder(binding.root){
        fun onBind(data: ToDo){
            binding.recyclerview = data

            binding.titleTextView.setOnClickListener {
                
            }//타이틀 클릭
            binding.deleteButton.setOnClickListener { 
                
            }//삭제 클릭
        }//onBind
    }//ViewHolder

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = TodoRecyclerviewBinding.inflate(LayoutInflater.from(context), parent, false)

        return ViewHolder(binding)
    }//onCreateViewHolder

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.onBind(data[position])
    }//onBindViewHolder

    override fun getItemCount(): Int {
        return data.size
    }//getItemCount
}

 - MainActivity

binding.recyclerView.layoutManager = LinearLayoutManager(this@MainActivity)

adapter = ToDo_RecyclerView_Adapter(this@MainActivity)
binding.recyclerView.layoutManager = LinearLayoutManager(this@MainActivity)
binding.recyclerView.adapter = adapter

viewModel.get_ToDo()

val recyclerView_data = Observer<List<ToDo>> {
    adapter.data = it
    adapter.notifyDataSetChanged()
}
viewModel.todo_data.observe(this@MainActivity, recyclerView_data)

 

반응형