오랜만에 면접을 보게 되었습니다. 무조건 '이직을 해야해' 하고 봤던 면접이 아니어서인지, 요즘 너무 공부를 안해서인지는 잘 모르겠지만, 스스로가 생각하기에도 제대로 답변을 못했다는 느낌이었는데, 아니나 다를까 불합격이었습니다. 사실 거기까지였으면 크게 신경 안썼을지도 모르겠습니다만, 면접 이후 피드백을 받은 건 되게 오랜만이라 면접을 복기하게 되었습니다.
확실히 생각보다 요즘은 새로운 트렌드를 따라가야 한다는 생각 때문인지, 기존에 사용하던 코드들을 왜 사용했는지, 그리고 왜 버렸는지 기억이 나지 않더라구요. 그래서 이번에는 이 부분에 대해서 한 번 살펴볼까 합니다.
이 글에 들어가기 전에 안드로이드의 데이터바인딩 라이브러리와 웹이나 다른 곳에서 사용하는 데이터바인딩은 유사하지만 조금씩 다른 측면을 가지고 있다는 것을 이해하고 글을 읽을 수 있으면 더 좋을 것 같습니다.
데이터바인딩이란, 연결된 특정 두 데이터 혹은 소스를 일치시키는 기법을 말합니다. 특정 데이터를 화면에 보여줘야 한다면, 그 데이터가 변경됨에 따라 화면에 보여지는 데이터도 변경되어야 하는데, 그 때 두 데이터를 여러가지 방법을 통해 묶어주는 개념인 것입니다. 여기서 제일 중요한 point는 '눈에 보이는 데이터와 실제 존재하는 데이터의 싱크를 맞추는 것'입니다.
그렇다면 안드로이드에서 data binding이라고 하는 친구가 무엇인지 먼저 살펴보겠습니다. 안드로이드의 dataBinding은 android jetpack의 라이브러리 중 하나로, 안드로이드의 xml 리소스에 data를 부착하는 것을 의미합니다. 그래서 이 데이터바인딩을 왜 사용하게 되는지 알아보겠습니다.
데이터바인딩의 장점
첫 번째 장점은 역시 dataBinding을 작성하게 되면, findViewById나 KTX를 이용한 synthetics view 호출이 사라진다는 점입니다. kotlin 코드 내에서 view를 호출하기 위해 따로 각 뷰를 불러오는 것이 아니라 DataBindingUtil과 같은 object를 이용해 binding class를 저장하고, 그 class를 이용해 각 뷰를 이용할 수 있어, 잘못된 id를 불러오는 실수등을 줄일 수 있습니다.
abstract class CommonFragment<T : ViewDataBinding>(@LayoutRes private val layoutId: Int) :
Fragment() {
private var _binding: T? = null
protected val binding: T get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = DataBindingUtil.inflate(
layoutInflater,
layoutId,
null,
false
)
binding.lifecycleOwner = this
return binding.root
}
}
databinding을 적용한 xml 리소스의 경우 자동으로 완성되는 BindingClass를 통해 그 class를 사용할 수 있게 작성할 수 있습니다. 위와 같이 작성하면 onViewCreated와 같은 곳에서 binding.viewId(자동으로 생성된 BindingClass)로 코드를 작성해서 사용할 수 있게 됩니다. 이는 그 xml에서 존재하지 않는 viewId는 class 변수로도 존재하지 않기 때문에 syntax error를 뱉어줍니다. 이를 통해 xml에서 작성한 모든 뷰를 이전보다 안전하게(null-safety) 사용하는 것이 가능해집니다. 이는 findViewById가 null-safety하지 못한 단점에 대한 불만과 KTX가 deprecated된 시점부터 압도적인 장점이 되었습니다. (물론 binding 역시 IO 코루틴 내에서 작업하다가 다시 Main 코루틴으로 변경해서 UI작업을 하는 형태로 코드를 작성하게 되었을 때 UI의 생명주기가 살아있는 상태임을 보장할 수 없을 때 NPE가 발생하긴 합니다. 하지만 정상적인 코드 형태에서는 null-safety하다고 여겨집니다.)
두 번째 장점은 LiveData와 같이 observe 변수와 함께 사용하는 경우, 데이터의 변경이 일어날 때 자연스럽게 연결된 UI도 업데이트시켜 UI와 데이터의 바인딩이 보장된다는 점입니다.(사실 이 기능이 없다면 데이터바인딩이라는 이름일 수 있을지 고민이 들긴 합니다.)
세 번째 장점은 xml에 <data></data> 내부에 변수를 작성하는 것으로 xml에서 사용할 데이터를 kotlin class 내부에 의지하지 않고 작성할 수 있다는 것입니다.
<?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="listViewModel"
type="com.myApplication.android.viewmodel.ListViewModel" />
</data>
<!-- layout code writing -->
</layout>
위와 같이 코드를 작성하면 <variable> 내부의 name을 통해 데이터를 작성할 수 있게 됩니다.
android:text="@{listViewModel.listName}"
위와 같은 방식으로 코드를 사용할 수 있는데, 이를 이용하면 추가적인 작업 없이 view에 data를 표현해줄 수 있습니다. 더 세부적인 상세 내용을 적는 등의 작업은(금액에 ,를 찍는다거나 하는 다른 가공 처리가 필요한 경우) bindingAdapter를 이용해서 작업을 진행할 수 있습니다. 이를 통해 뷰에서 직접 데이터를 관리하는 느낌과 한 곳에 위치한 데이터와 UI를 통해 전체적인 가독성을 상승시킬 수 있습니다.
android:text="@={viewModel.encouragementMessage}"
또한 위와 같이 EditText에서 @{ 가 아니라 @={로 시작하는 경우 양방향 데이터바인딩이 이루어져 EditText가 가진 변수와 @={}안에 들어간 변수가 싱크를 유지하며 동일한 데이터로 매칭됩니다. 이처럼 UI내에서 변수를 가지게 되는 경우에는 양방향 데이터 바인딩을 사용할 수 있습니다.
데이터바인딩의 단점
안드로이드 데이터바인딩의 첫 번째 문제점은 각 xml 파일마다 BindingClass가 추가적으로 생성된다는 점입니다. 이때문에 앱의 기본적인 용량의 상승을 피하기 어렵고, 빌드의 속도가 느려져 전체적인 개발 속도에 영향을 미칠 수 있습니다.
두 번째 문제점은 xml 파일은 안드로이드 스튜디오에서 코틀린이나 자바로 만든 코드보다 훨씬 디버깅이 어렵다는 점입니다. 기본적으로 XML 어디 라인에서 에러가 났습니다를 알려주는 경우도 분명 존재하지만, 특정 에러를 제외하고는 xml에서 에러가 나는 경우 전혀 다른 exception을 발생하는 등의 문제를 일으키기 때문에, 기존 code에서 작성하는 것 보다 더 세심한 주의가 필요합니다. 또한 문제가 나도 발견하기 어렵기 때문에 잘 살펴봐야 하기도 합니다.
결론
사실 안드로이드 데이터바인딩을 사용하는 데 있어 장단점은 크게 중요하지 않아지고 있습니다. 그 전에 사용하던 synthetics가 deprecated되면서 일단 이전 버전 UI는 더이상 제공되지 않기 때문에, 추후 안드로이드 타깃 api를 올리기 위해서라도 어쩔 수 없이 다음 버전 UI 코드나 findViewById를 사용해야 하는데, findViewById는 id 확인을 위해 ViewGroup을 전부 돌면서 확인한다는 그 로직이 속도면에서 느림을 인정받았고, 사실상 안정성 면에서도 불합격을 받았기 때문에 거의 지양하는 코드가 되었고, google에서도 안드로이드 스튜디오 버전이 올라가면서 자동으로 생성해주는 코드가 ViewBinding UI가 되었기 때문에 선택권이 사실상 사라진 셈입니다.
그래서 안드로이드 UI를 작성할 때 데이터를 전달해야 하는 경우 DataBinding을, 간단한 UI작업만을 위해서는 ViewBinding을 사용하는 등의 선택권 정도가 남았습니다.(물론 현재 jetpack compose 라는 구글에서 밀어주는 다음 버전의 UI Toolkit이 존재하기 때문에 또 추후에는 UI 코드가 변경될 예정이라고 볼 수 있습니다.)
데이터 바인딩이 처음 나왔을 때, 구글에서도 반응형 코드가 필요하다는 판단을 했다는 생각이 들었습니다. 그래서기존 코드와 함께 rxJava가 아닌, 안드로이드의 주인인 구글에서 제공해주는 DataBinding으로 작업을 하는 것이 훨씬 더 효율적일 것이라 생각도 했죠. 그러나 가장 집중해야할 점은 그러한 성능면의 이슈가 아닌 구글이 언제 또 안드로이드의 트렌드를 바꿔나갈지 모른다는 점이고, jetpack compose 까지 나온 지금에서야 드는 생각은 안드로이드 개발자로서 계속 공부해나간다고 한들 과연 추후에 쌓인 연차가 과연 도움이 될까 하는 의문이 들게 되는 것 같습니다.
다시 생각해보면 Jetpack 라이브러리를 기본으로 한 안드로이드 책을 통해 공부한 친구와 새로 배우는 제가, 속도면에서는 차이가 있겠지만 그 이전에 배웠던 모든 것들이 과연 손실없이 다음 단계에서 보전이 되느냐 하는 점에서 본다면 결국 제가 배웠던 부분들의 일정부분은 잃어버리는 셈이니(어쩌면 이때까지 배워왔던 것들이 모두 사라져버릴지도 모르는) 안정적인 프레임워크인가에 대한 생각이 많이 듭니다.
결국 저도 추후에는 백엔드 개발자로서 작업을 시작하게 될 것이고 어떤 분야든 개발자라면 평생을 공부해야하는 것은 틀림이 없지만, 아직까지 안드로이드 개발자라는 이름을 달고 있는 지금은 구글의 이러한 정책과 변화들이 달갑지는 않은 것 같습니다.
'안드로이드 > 기타' 카테고리의 다른 글
ANR(Application Not Responding)이란? (0) | 2022.08.06 |
---|---|
LiveData vs RxJava (0) | 2022.07.08 |
안드로이드 앱 실행 시간(cold, hot, warm start) (1) | 2021.10.20 |
안드로이드 관련 유용한 오픈소스 및 라이브러리 링크 (0) | 2021.04.23 |
xml로 버튼 커스텀 하기(selector) (0) | 2021.02.22 |
댓글