[개념] 데이터 바인딩(data Binding) (2)

쓰리원·2022년 5월 8일
0

binding 정리

목록 보기
3/6
post-thumbnail

binding 글 링크

개념-데이터-바인딩data-Binding (1)
개념-데이터-바인딩data-Binding (2)
개념-데이터-바인딩data-Binding (3)
개념-데이터-바인딩data-Binding (4)
개념-데이터-바인딩data-Binding (5)

1. 사전 배경 개념 설명

View의 이벤트 처리방법에는 익명 클래스 or 인터페이스 구현(Implements) 등 여러 방법이 존재합니다.

//1. 람다식
button.setOnClickListener(view -> Log.d(TAG, "Click"));

//2. 익명 클래스
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    	Log.d(TAG, "Click");
    }
});
//3. 인터페이스 구현 (implements)
public class MainActivity implements View.OnClickListenr {
   
    button.setOnClickListener(this);

    @Override
    public void onClick(view v) {
        Log.d(TAG, "Click");
    }
}

2. data binding 라이브러리 사용

1. 이벤트 처리

DataBinding을 메서드 또는 리스너를 바인딩 하여 이벤트 처리를 할 수 있습니다. 컴파일 시 처리가 되므로, 바인딩 하려는 메서드가 존재하지 않거나 잘못 되었을 경우 런타임 에러가 발생하는 것이 아니라 컴파일 에러가 발생합니다. 데이터 바인딩을 이용한 방법에는 메서드 참조, 리스너 바인딩 두 가지 방법이 있습니다.

  • 메서드 참조 : 클래스에 선언된 메서드를 데이터 바인딩을 통해 xml에서 직접 바인딩이 가능합니다.
  • 리스너 바인딩 : 임의의 데이터 바인딩 식을 이용할 수 있습니다.

2. 메서드 참조하는 방식

class MyHandlers {
	fun onClickFriend(view: View) { ... }
}

결합 표현식은 다음과 같이 뷰의 클릭 리스너를 onClickFriend() 메서드에 할당할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="handlers" type="com.example.MyHandlers"/>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView 
           		android:layout_width="wrap_content"
               	android:layout_height="wrap_content"
              	android:text="@{user.firstName}"
                android:onClick="@{handlers::onClickFriend}"
                />
       </LinearLayout>
    </layout>

TextView에 android:onClick="@{handlers::onClickFriend}"로 정의 함으로써,메서드를 직접 바인딩 하였습니다. "variable::메서드명" 이 아닌 "variable.메서드명" 으로 작성해도 동작 하지만 deprecated 되어 "::" 사용을 권고하고 있습니다.

또한, 바인딩 하려는 메서드는 해당 리스너의 메서드 형태와 동일 해야 합니다. 예를들어 onClick 메서드의 경우, 아래와 같은 형태이므로 return type 이 void 이고 매개변수로 View 가 있으므로 이 형태로 바인딩 메서드를 작성 해야합니다.

마지막으로 레이아웃 파일에 추가한 MyHandlers 객체를 설정 합니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

    binding.handlers = MyHandlers()
}

3. 메서드 참조 구현 코드

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="handlers" type="com.project.databindingevent.MyHandlers"/>
        <variable name="user" type="com.project.databindingevent.User"/>
    </data>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="50sp"
            android:text="@{user.firstName}"
            android:onClick="@{handlers::onClickFriend}"
            />
    </LinearLayout>
</layout>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        binding.user = User("Test", "User")
        binding.handlers = MyHandlers(this)
    }
}

data class User(val firstName: String, val lastName: String)

class MyHandlers(val context : Context) {
    fun onClickFriend(view: View) {
        Toast.makeText(context, "Click", Toast.LENGTH_SHORT).show()
        Log.d(TAG, "Click")
    }
}

코드 링크 : https://github.com/ilil1/dataBindingEvent

4. 리스너 바인딩 하는 방식

class Presenter {
	fun onSaveClick(task: Task){}
}
<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable name="task" type="com.android.example.Task" />
            <variable name="presenter" type="com.android.example.Presenter" />
        </data>
        <LinearLayout
				android:layout_width="match_parent"
                android:layout_height="match_parent">
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            	android:onClick="@{() -> presenter.onSaveClick(task)}"/>
        </LinearLayout>
    </layout>

리스너는 람다 형태로 표현 합니다. 바인딩이 필요한 이벤트 리스너를 자동으로 생성하고, 이벤트가 발생하면 바인딩 된 식을 실행하는 형태입니다.

위의 예시에서는 onClick(view : View) 로 전달되는 view 매개변수를 지정하지 않았습니다. 리스너를 바인딩 할때는 모든 매개변수를 지정하거나, 지정하지 않고 사용 할 수 있습니다. 매개변수를 지정하면 메서드에 해당 변수를 그대로 사용 할 수 있습니다. 예시는 아래와 같습니다.

class Presenter {
	fun onSaveClick(view: View, task: Task){}
}

android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"

이때 리스너 안에 바인딩 된 식은 발생한 이벤트 리스너의 return type 과 동일한 type 을 return 해야 합니다.

위에 data태그 안의 variable를 선언해줍니다.

data class Task(val firstName: String, val lastName: String)의 값으로 임의의 데이터 결합 표현식을 실행할 수 있습니다.

android:onClick="@{() -> presenter.onSaveClick(task)}" 리스너 바인딩은 메서드 참조와 달리 리턴타입만 일치시키면 됩니다

return type void만 일치시켜 줍니다.

5. 리스너 바인딩 구현 코드

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

    <data>
        <variable
            name="task"
            type="com.project.databindingeventlistener.Task" />

        <variable
            name="presenter"
            type="com.project.databindingeventlistener.Presenter" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.onSaveClick(task)}"
            android:text="버튼"
            android:textSize="100sp" />
    </LinearLayout>
</layout>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        binding.task = Task("Test", "User")
        binding.presenter = Presenter(this)
    }
}

class Presenter(val context : Context) {
    fun onSaveClick(task: Task){
        Toast.makeText(context, "${task.firstName}, ${task.lastName}" , Toast.LENGTH_SHORT).show()
    }
}

data class Task(val firstName: String, val lastName: String)

코드 링크 : https://github.com/ilil1/dataBindingEventlistener

3. reference

https://developer.android.com/topic/libraries/data-binding/start
https://developer.android.com/topic/libraries/data-binding
https://developer.android.com/topic/libraries/data-binding/expressions

profile
가장 아름다운 정답은 서로의 협업안에 있다.

0개의 댓글