INTRO
Android Kotlin에서
일반적으로 View를 제어하는 방법과,
이를 보다 편리하게 해주는 View Binding을 사용하는 방법
그리고 조금 더 발전한 DataBinding을 사용하는 방법에 대해 포스팅한다.
0. 준비
우선 아래와 같은 레이아웃을 만들고, TextView, EditText, Button을 하나씩 배치했다.
버튼을 클릭할 때 EditText에 있는 내용을 TextView로 Set 하는 기능을 3가지 방법으로 만들어보고자 한다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="268dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="168dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editText1"
android:layout_width="320dp"
android:layout_height="52dp"
android:layout_marginTop="80dp"
android:ems="10"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
1. 기초적인 방법으로 제어하기
아래와 같이 findViewById 메서드를 이용하여 View객체를 얻어온 후, 해당 View의 get/set메서드를 호출하여 제어하는 방법이다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var textView = findViewById<TextView>(R.id.textView1)
textView.text = "this is TextView"
findViewById<Button>(R.id.button1).setOnClickListener{
val editText : String = findViewById<EditText>(R.id.editText1).text.toString()
findViewById<TextView>(R.id.textView1).text = editText
}
}
여기서 이렇게 매 번 findViewById 메서드를 호출하는 것이
1. 불편하기도 하고,
2. View 내부를 전체 순회하여 속도가 느리며,
3. Null Safe 하지 못하다는 단점이 있다고 한다.
이를 보완하고자 ButterKnife 라는 라이브러리 출시되었으나, 이 또한 쓸데없는 코드가 많이 발생함.
@BindView(R.id.textView1) val textView : TextView
이후 kotlin-android-extension 이라는 기능이 추가되어, 아래와 같이 gradle에 추가하고, MainActivity에서 import 하면 findViewById를 사용하지 않아도 되었다. 내부 캐싱을 통한 재사용성도 높아졌다고 한다.
plugins {
id 'kotlin-android-extensions'
}
textView1.text = "this is TextView"
하지만 여기에도 단점이 존재했으니..
- null-safe가 제한적으로 적용되며,
- 같은 ID를 가진 다른 레이아웃을 참조할 수도 있고,
- kotlin에서만 사용할 수 있다.
이로 인해 kotlin 1.4.20부터는 deprecate 되었다.
위 단점들을 보완하고자 나온것들이 ViewBinding과 DataBinding이다.
이 2가지는 현재까지 활발히 사용되며, 각각의 특징이 있다.
2. ViewBinding을 통해 제어하기
build.gradle 에 아래와 같이 추가한다.
android {
.
.
.
// Binding 설정
buildFeatures{
viewBinding true
}
}
MainActivity.kt 에 아래와 같이 작성한다.
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView1.text = "this is TextView"
binding.button1.setOnClickListener{
binding.textView1.text =binding.editText1.text
}
}
}
위의 [기초적인 제어] 코드와 비교했을 때, 사용 방법이 보다 명확해지고 간결해진 것을 볼 수 있다.
현재 코드는 3개 정도의 View만 있기 때문에 코드량의 차이가 많이 없어보일 수 있으나, 더 많아졌을 때를 생각해본다면..?
또한 ActivityMainBinding = activity_main.xml 이기 때문에 null 위험도 줄어든다.
3. DataBinding을 통해 제어하기
build.gradle에 아래와 같이 추가한다.
android {
.
.
.
// Binding 설정
buildFeatures{
dataBinding true
}
}
MainActivity.kt 를 아래와 같이 ViewBinding처럼 작성할 수도 있다.
Binding이 된 상태이기 때문이다.
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.textView1.text = "this is TextView"
binding.button1.setOnClickListener{
binding.textView1.text =binding.editText1.text
}
}
}
하지만 이렇게 사용한다면 DataBinding의 특징을 사용한 것이라고 볼 수 없다.
DataBinding의 특징을 좀 더 잘 살려보자
activity_main을 아래와 같이 <layout> 코드로 감싸주고, <data> 태그 선언 후 안에 <variable>태그를 선언한다.
간략하게 설명하자면, MainActivity클래스를 activity라는 이름으로 연결(Binding)해준다.
이후 MainActivity클래스 안에 있는 멤버변수들을 각 View에 @{activity.text1}과 같은 형태로 연결해준다.
주의해서 봐야 할 점은, EditText에는 @={activity.text2} 와 같이 적혀있는 것을 볼 수 있다.
이는 Activity -> XML 방향으로만 바인딩 하는 것이 아니라 Activity <-> XML 과 같이 양방향 바인딩을 한다는 말이다.
EditText에 있는 Text를 가져와 TextView에 다시 set하기 위해 양방향 바인딩이 필요하다.
<?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" >
<data>
<variable
name="activity"
type="com.example.viewcontrolbindingtest.MainActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="268dp"
android:text="@{activity.text1}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="168dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editText1"
android:layout_width="320dp"
android:layout_height="52dp"
android:layout_marginTop="80dp"
android:ems="10"
android:text="@={activity.text2}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity.kt에 아래와 같이 작성한다.
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
var text1 : String = ""
var text2 : String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.activity = this@MainActivity
text1 = "this is TextView"
binding.button1.setOnClickListener{
text1 = text2
binding.invalidateAll()
}
}
}
여기까지 왔다면 3가지 방법에 대한 감이 올 것이다.
DataBinding은 위와 같이 단독으로 사용될 때 보다는
Data class, ViewModel등과 같이 사용되어 MVVM패턴을 구축할 때 효율적이다.
또한 button Click 이벤트도, 별도의 메서드를 만들어서 xml의 button 태그 내 아래와 같이 사용할 수도 있다.
android:onClick="@{() -> activity.onSaveClick()}"
마무리
여기까지 View를 제어하는 3가지 방법에 대해 알아보았다.
이를 Activity에 사용할때는 위와 같이 사용하면 되지만, Fragment에서는 사용 방법이 또 다르다.
이 방법도 함께 알아보는 것을 추천한다.
-퍼가실 때는 출처를 꼭 같이 적어서 올려주세요!
'Dev > [Android]' 카테고리의 다른 글
[Android Kotlin] Activity에 Fragment 올리기 (0) | 2022.01.19 |
---|---|
[Android + Kotlin 시작하기] 간단한 App 만들어보기 - 2 (0) | 2021.12.27 |
[Android + Kotlin 시작하기] 간단한 App 만들어보기 - 1 (0) | 2021.12.27 |
[Android] SHA값 추출 (0) | 2021.05.19 |