기존에 안드로이드를 처음 배웠을때 공부했었던 프로젝트들을 복습하려고 열어본결과
이렇게 Kotlin Android Extensions이 deprecated 되었다며 대체 할거로 viewbinding이나 databinding을 이용하라고 한다.
그래서 Kotlin Android Extensions은 왜 팽당했는가, Viewbinding,databinding 은 무엇이며 어떻게 사용해야 하는가를 알아 보려한다.
우선 이것들이 뭣 때문에 하는지 알아보자
xml 파일의 뷰들을 java파일에서 이벤트 처리를 위해 사용하려면
메모리에 올라와있어야 하는데 그래서 액티비티의 onCreate() 에서 setContentView()를 통해 인플레이션을 한다.
인플레이션이란 xml 레이아웃 파일 안에 들어있는 뷰 태그들을 이용해 뷰 객체를 메모리에 만드는 과정 즉 자바파일에서 xml을 만질수 있도록 연결해주는것이라 대략적으로 생각하면 될것같다.
이렇게 xml 레이아웃 파일의 내용을 메모리에 객체로 만들고 소스코드에서 그 객체들을 찾아서 이용하는것이다.
이때 객체는 findViewByid 메서드를 이용하여 찾고 xml에서 만든 id를 파라미터로 사용합니다.
1.Kotlin Android Extensions은 왜 팽당했는가
kotlin android extensions 을 4.1버전 이후 기본 플러그인에서 삭제되었고 그이후에도 나는 직접 추가해서 사용해왔는데
deprecated 되었다고 사용하지 말란다. 우선 장단점을 보자
장점 :
1.간편하다
그냥 플러그인에 한줄띡 추가하면 findViewById 일일이 할필요없이 편해진다.
그냥 이거 한줄 추가하면 id를 바로 가져다 쓸수있다.
2. 재사용성
내부적으로 캐싱을 통해 재사용성을 높인다고한다.
단점:
1. RecyclerView의 ViewHolder 사용 시 문제점
사실 findViewById()는 똑같은 코드를 계속 써줘야 한다는 귀찮음도 있지만, 해당 메소드를 자주 호출하면 성능 저하의 문제점도 있다. 그런데 RecyclerView에서 KAE를 쓰고 java로 디컴파일했더니 findViewById()를 쓰고 있었다.
결국 RecyclerView 에서는 KAE를 사용하면 내부적으로는 findViewById() 를 계속 사용한다는 것이고 성능이 저하된다는것이다.
(findViewById 관련된것 잘못된 정보란다 리사이클러 뷰홀더관련 메모리가 안없어지는게 문제였다고한다 -> 메모리릭이 너무 치명적이라 없어졌다고한다)
2022.09.29 추가내용 여태까지 이런것들을 애매하게 주변에서 들은 것들을 토대로 깊지않게 구글링해서 넣은부분이였다 사실 쓰지말아야하는 기술 아예 안보이는 기술이 왜 없어졌냐 까지 자세하게 알아야하나 싶어서였는데 그래도 블로그에다 올리는건데 이상한내용이 있는것은 용납할수없어 추가자료를 첨부한다 위의 헛소리는 그냥 레거시 코드처럼 옛날에 내가 저렇게 생각했었구나 라고 남겨는 놓으려고한다
https://thdev.tech/android/2020/10/07/Remove-kotlinx-synthetic/
이부분에 대해 작성하기 시작하면 또 한세월이니 좋은 자료를 첨부하려고한다.
2.뷰가 동일한 id를 가지는 경우 상황이 애매해진다
같은 id를 사용하는 view가 있을 경우 혼선이 올수있다.
이렇듯 문제점이 있기에 이제 더이상 사용하지 않고 대체제로 Viewbinding이나 Databinding을 쓴다.
2.그래서 Viewbinding이 뭔데 ?
그래서 안드로이드에서는 kotlin android extensions의 대체제로써 Viewbinding을 추천하고있다.
View Binding이란?
뷰 바인딩(View Binding) 은 뷰와 상호 작용하는 코드를보다 쉽게 작성할 수있는 기능이다. 모듈의 build.gradle에서 뷰 바인딩 속성이 활성화되면 해당 모듈에있는 각 XML 레이아웃 파일에 대한 바인딩 클래스가 자동으로 생성된다. 바인딩 클래스 인스턴스에는 해당 레이아웃에 ID가 있는 모든 뷰에 대해 직접적으로 참조된다.
대부분 경우에 있어, 뷰 바인딩을 사용하는 것으로 findViewById 메서드를 대체할 수 있다.
한마디로 뷰바인딩을 활성화시키면 바인딩클래스를 안드로이드가 만들어주고 그것을 id를 통해 직접적으로 이용할수있는것이다. 이걸로 findViewById를 대체할수있다.
사용법을 봐보자
1.액티비티에서 사용법
우선 build gradle(module)에
이걸 추가해줘야한다.
현자 문다빈의 조언이다 이렇게 바뀌어서 이렇게 사용하는게 좋다고한다.
또한 바인딩 클래스를 생성하는 동안 레이아웃 파일을 무시하려면 tools : viewBindingIgnore = “true” 속성을 해당 레이아웃 파일의 최상단 루트에 추가해야한다.
이제 안드로이드가 바인딩 클래스를 자동으로 생성해주는데 거기에는 루트뷰 및 Id가 있는 모든 뷰의 참조가 포함된다.
이제 사용을위해 이름을 알아야할것이다.
그이름이 중요한데 XML 파일의 이름을 Camel case로 변환하고 접미어 “Binding” 을 추가하면된다.
예시로 레이아웃 파일 테스트 위해만든 MainActivity의 xml 파일이름은 activity_main이므로
이것의 바인딩 클래스의 이름은 ActivityMainBinding이다.
고로 생성된 바인딩 클래스의 인스턴스를 얻으려면 inflate() 메서드를 호출한다.
그후 setContentView()에 매개변수로 루트뷰(xml파일에서 가장 상위에있는 레이아웃)를 전달하여 화면에서 활성화된 뷰를 만들면 된다.
이제 바인딩 클래스의 인스턴스로 모든뷰를 참조할수있다.
이렇게 findViewById 없이도 뷰에 접근가능하다.
2. 프래그먼트에서 사용법
마찬가지로 적용해주면된다.
최초의 프래그먼트가 이런상태라면
이런식으로 적용하면된다.
이거는 대략적인 기본코드를 비교해서 보여주기 위한것이고 실제로 사용할때는 kotlin property를 활용 binding변수의 getter을 정의하며 사용한다.
그리고 프래그먼트가 메모리에서 날아갈때 즉 사라질때 바인딩 인스턴스도 날려줘야한다. 바인딩 인스턴스도 날려버리기위한 코드도 추가해준다
이렇게 onDestoryView시점에 담겨있던 액티비티가 없어질때
binding에 담아놨던 바인딩 인스턴스도 null값으로 덮어버려 메모리를 날려버린다
간단하게 이런식으로 사용하면된다.
이렇게 뷰바인딩을 통해 바인딩클래스를 가져와서 바로바로 사용할수있는 코틀린코드에서 뷰를 참조할수있는 방법을 알아보았다.
뷰바인딩의 장점과 단점을 알아보자
장점
findViewById와의 차이?
- null safety - 뷰 직접 참조로 없는 아이디로 널포인트 익셉션 발생 안한다.
- type safety - 뷰 타입이 일치함으로 Class Cast Exception 발생 안한다.
DataBinding과의 차이?
일단, 둘은 모두 뷰를 직접 참조하는데 사용할 수 있는 binding class 를 제공한다.
확실히 viewbinding은 보다 단순한 처리의 경우 적합.
- 더 빠른 컴파일 = annotation처리 필요 없음으로 컴파일이 빠르다.
- 사용 편의 - tag처리된 xml 불 필요로 사용 용이. (모듈에서 binding 사용 설정만을 통해 자동으로 모든 레이아웃의 binding class 생성)
단점
DataBinding과의 차이에서 오는 단점?
- layout에서의 표현식 혹은 변수 제공하지 않으므로 동적인 UI 콘텐츠 생성 할 수 없다.
- two-way- data binding 제공 안한다. (ex. bindingAdapter) 공식문서
2022.09.29 추가
viewbinding,databinding 모두 구글 공식문서에서 쓰라고 권장한다 뭐가 좋고 나쁘고는 없고 적절한 상황에서 사용하면된다. 온보딩같이 뭐딱히 선언적으로 연결해줄 필요조차 없을경우 빠른속도를위해 뷰바인딩을 적절히 혼용해주면 될것같다
3.이제 데이터 바인딩을 살펴보자
데이터 바인딩 또한 xml과 데이터를 직접연결해서 view를 코드에서 만지지는 용도 + 데이터를 바인딩(묶다) 즉 선언적으로 뷰에다가 데이터를 꽃아 버리는것이다.
vue에서 html에다가 그냥 직빵으로 변수 집어넣는것처럼 xml상에서 view에다가 변수를 연결시켜 버리면 그 변수 값에따라 화면단에서 데이터를 표시해준다.
vue에서처럼 데이터를 바꾸면 실시간으로 화면단까지 바뀌는것은 livedata와 함께 쓰면 구현할수있다 우선은 글이 너무 길어지니 그것은 다음글에서 다뤄보도록 하겠다.
생각해보자 vue에서 데이터 바뀌면 화면도 같이바뀌니 얼마나 편했던가 그걸 직접만들어야 하는게 화가나지만 어쨋든 할수있음에 감사하자
databinding 의 장점을 살펴보면
데이터 소스가 변경될때 ui 새로고침에 대해서 신경안써도되고(물론 라이브데이터 같이써야함)
ui호출하는 코드 없어지니 코드가 간결해지고
앱의 성능을 개선하고 메모리 누수 및 nullpointerexception 을 방지하는데 도움된다.
이제 사용법을 봐보자
1.app 수준의 Build.gradle 파일 수정
* 위와 같이 dataBinding을 추가해주면 아래 사진처럼 kotlin-kapt plugin을 설정하라고 나옵니다.
사진처럼 안내 문구가 뜬다면 맨위쪽에 아래 코드를 추가합니다.
2. DataBinding을 사용 할 xml 파일 수정
data binding 사용하려면 xml 리소스는 <layout>태그를 루트태그로 가져야한다.
고로 기존의 있던 내용들을 <layout>태그로 감싸주자
3. 사용하려는 Activity에서 binding Setting
뷰바인딩처럼 카멜케이스로 똑같은 이름의 객체 생성되는데 그 자료형으로 변수 만들고
거기에 DataBindingUtil.setContentView(this, 액티비티에 맞는 레이아웃) 이 함수를 통해 setContentView를 대체해준다.
4.view에서 보여줄 것들을 담은 dataclass 선언(생략가능)
데이터 클래스로 데이터 모아놓고 관리할꺼면 data class를 만들어준다 필요한것들 맞춰서
5. xml 파일에서 data 정의
이제 xml파일에서 <data>요소를 작성해준다
<data> 태그는 <layout> 에서 사용할 변수를 정의하는데 사용된다.
name은 이제 xml안에서 변수 이름을 뜻하는것이라 생각하면되고
좀있다가 코틀린파일에서 binding.name에 정의한거 = 데이터클래스 인스턴스 이런식으로 데이터를 연결시켜서 xml에서 꺼내 쓸수있게 해주는것이다.(한마디로 xml에 변수 선언해놓고 코틀린파일에서 거기에 원하는 인스턴스 넣고 그대로 뽑아서 선언적으로 연결시켜주는것이다.)
type은 이제 자료형 느낌으로 data class를 이용한다면 그 클래스나 아니면 액티비티를 직접 연결시켜서 어느 클래스를 가져다 쓸거냐를 적으면된다 적는어야하는 내용은 (내 패키지명 + 액티비티 명 또는 프래그먼트 명) 이다.(2022.09.29 이제와서 보니까 너무 헛소리를 많이해서 웃기고 부끄럽긴한데 어쩃든 당연히 액티비티니 이런거 안연결시키고 왠만해서 그냥 단독변수 혹은 뷰모델을 연결시키게 될것이다)
나는 자기소개에 대한 내용이었기에 name를 introduce로 했고
type은 data class를 따로 만들어서 데이터를 사용했기에 데이터 클래스의 패키지명+클래스명을 넣어줬다.
만약 액티비티에 바로 변수 선언하고 그거사용할꺼면
이런식으로 액티비티를 넣어줘도된다.
6.Activity에 dataclass 초기화 및 binding객체에 dataSource set하기
데이터 클래스를 초기화 시키고 그것을 binding 객체에 넣어주어서 연결시켜준다.
그리고 만약 data class안쓰고 바로 액티비티에 변수 선언해주고 그거 사용하고싶다면
이렇게 액티비티에서 변수 만들고
binding객체에는 this를 넣어준다.
7.xml에 원하는 뷰들에 선언하기
이제 마지막으로 text같이 데이터가 연결되는곳에 name으로 지정했던 introduce.변수명 을 @{} 로 감싸서 데이터를 뷰에 연결시켜버린다. 이미지의 표현식은 변수와 함께 문자열도 표현하고싶을때 @{`문자열`+변수명}으로 표현해주면 된다.
이렇게 databinding의 간단한 사용법을 알아보았다.
프래그먼트에서 databinding
Fragment에서 데이터 바인딩 사용하기
Fragment에서 데이터 바인딩을 사용할 때는 Activity와 거의 같지만 binding을 받아오는 코드가 살짝 다르다. 기존에 inflater로 inflate하는 방식과 유사한 방식으로 가져오면 된다.
// Activity
val binding = DataBindingUtil.setContentView(this, layoutResourceId)
// Fragment
val binding = DataBindingUtil.inflate(inflater, layoutResourceId, container, false)
또한 데이터 바인딩 또한 Fragment 에서 사용할때는 라이프 사이클과 관련하여 메모리 누수가 발생할수있기에 뷰바인딩에서 프래그먼트에 적용한것처럼 onDestroyView 에서 null값을 넣을수있도록 만들어줘야한다.
class CameraFragment : Fragment() {
private var _binding : FragmentCameraBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = DataBindingUtil.inflate(inflater,R.layout.fragment_camera, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
이런식으로 작성해줘야 메모리 누수를 막을수있다.
추가적으로 이미지 같은것들을 관리하고싶다면 bindingAdapter을 추가적으로 사용해야하고
livedata와 같이 사용한다면 찰떡같이 사용할수있으니 그런 부분들도 추후에 알아보도록 하겠다.
+ 추후에 two way binding과 bindingAdapter에 관한 설명글도 작성하도록 하겠다.
출처: https://velog.io/@deepblue/Kotlin-Android-Extensions%EC%9D%B4-deprecated%EB%90%9C-%EC%9D%B4%EC%9C%A0
https://charlezz.medium.com/view-binding-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-df3526d909a7
https://www.youtube.com/watch?v=J_e8N7vwCFI&t=547s
https://velog.io/@jojo_devstory/Android-Databinding%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90
https://dev-imaec.tistory.com/37
https://salix97.tistory.com/243
'안드로이드' 카테고리의 다른 글
databinding의 Two-way Binding (0) | 2021.11.01 |
---|---|
리사이클러 뷰에 databinding적용해보기 (0) | 2021.11.01 |
디자인패턴의 전반 mvc,mvp,mvvm을 알아보자 (0) | 2021.10.19 |
data binding 과 live data 동시 적용해보자 (0) | 2021.10.14 |
LiveData 찍먹 해보자 (0) | 2021.10.12 |