결론부터 말씀드리면, View Binding이나 Data Binding을 사용하면서 Kotlin의 특정 기능을 활용하면 Butter Knife와 매우 유사한 직관성을 얻을 수 있습니다. 하지만 순수 Java 환경에서는 그와 동일한 수준의 직관성을 구현하기는 어렵습니다.
언어별로 나누어 설명해 드리겠습니다.
1. Kotlin 환경: 위임된 프로퍼티(Delegated Properties)를 통한 해결
Kotlin은 이 문제를 매우 우아하게 해결할 수 있는 ‘위임된 프로퍼티’라는 강력한 기능을 제공합니다.
어떻게 가능한가?
커스텀 델리게이트를 만들어, 뷰에 처음 접근할 때 binding 객체에서 해당 뷰를 찾아 반환하고 그 값을 캐싱(caching)하게 할 수 있습니다. 이렇게 하면 마치 뷰가 클래스의 프로퍼티인 것처럼 직접 사용할 수 있습니다.
사용 예시 (Fragment에서):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class MyFragment : Fragment(R.layout.fragment_my) { // ViewBinding 프로퍼티 델리게이트 (직접 만들거나 라이브러리 사용) private val binding by viewBinding(FragmentMyBinding::bind) // Butter Knife와 거의 동일한 직관성! private val titleTextView: TextView by viewBinding() private val submitButton: Button by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 이제 'binding.' 접두사 없이 바로 사용 가능 titleTextView.text = "Hello Delegated Properties!" submitButton.setOnClickListener { // 클릭 이벤트 처리 } } } |
by viewBinding()이라는 코드가 마법처럼 작동하여,titleTextView에 처음 접근할 때binding.titleTextView를 찾아 반환해 줍니다.- 이를 구현해주는
ViewBindingPropertyDelegate같은 오픈소스 라이브러리들이 존재하여 쉽게 적용할 수 있습니다. - 결과적으로 Butter Knife의
@BindView와 거의 100% 동일한 직관성과 가독성을 얻으면서, View Binding의 컴파일 타임 안전성이라는 장점은 그대로 가져갈 수 있습니다.
2. Java 환경: 왜 똑같이 구현하기 어려운가?
Java에는 Kotlin의 ‘위임된 프로퍼티’와 같은 언어적 기능이 없습니다. 따라서 Butter Knife처럼 필드를 선언하고 자동으로 값을 할당받는 매끄러운 경험을 구현하려면, 결국 **리플렉션(Reflection)**이나 **어노테이션 프로세싱(Annotation Processing)**에 의존해야 합니다.
하지만 이것이 바로 Butter Knife가 사용했던 방식이며, 현재 안드로이드 개발에서 지양하는 이유(성능 저하, 런타임 에러 위험)이기도 합니다.
그렇다면 Java에서는 최선이 무엇일까?
순수 Java 환경에서는 아쉽지만 Butter Knife와 ‘똑같은’ 직관성을 제공하는 공식적인 방법은 없습니다. 따라서 binding 객체를 통해 접근하는 것이 표준이자 가장 권장되는 방법입니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // 'binding.' 접두사를 붙여서 사용하는 것이 표준입니다. binding.textViewTitle.setText("Hello View Binding!"); binding.buttonSubmit.setOnClickListener(...); } } |
차선책 (권장하지 않음): 멤버 변수에 직접 할당하기
굳이 필드로 선언해서 사용하고 싶다면, onCreate에서 수동으로 할당해 줄 수는 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; // 필드를 미리 선언 private TextView titleTextView; private Button submitButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // onCreate에서 수동으로 할당 this.titleTextView = binding.textViewTitle; this.submitButton = binding.buttonSubmit; // 이제 필드를 통해 접근 가능 titleTextView.setText("Hello View Binding!"); submitButton.setOnClickListener(...); } } |
- 단점:
- 모든 뷰에 대해 중복되는 할당 코드가 생깁니다.
binding.을 붙이는 것보다 코드가 더 길어지고 지저분해집니다.- Butter Knife의 간결함이라는 장점이 전혀 없습니다.
- 결과적으로
binding.textViewTitle로 직접 사용하는 것보다 나을 게 전혀 없습니다.
결론
| 언어 | @BindView와 동일한 직관성 구현 |
추천 방법 |
|---|---|---|
| Kotlin | 가능 (위임된 프로퍼티 활용) | 위임된 프로퍼티를 사용하여 binding 접두사 없이 뷰를 직접 프로퍼티처럼 사용. |
| Java | 불가능 (권장되지 않음) | binding.viewId 형태로 binding 객체를 통해 직접 접근하는 표준 방식을 따르는 것이 최선. |