안드로이드 개발을 하다보면 View 객체의 속성을 xml 파일에서 선언하여 줄 수 있지만 Java나 Kotlin 코드에서 View 객체를 다뤄야하는 상황이 발생합니다.
오늘은 이처럼 View 객체를 가져오는 방법 중 첫번 째로 findViewById()
와 Kotlin Android Extensions에 대해 알아보도록 하겠습니다.
findViewById()
안드로이드 초창기에 Java로만 안드로이드를 개발할 수 있던 시절부터 사용되어 왔던 선조 격인 방법입니다. 사용방법은 이렇습니다.
1) xml 파일에서 View의 id를 정의한다.
2) Java나 Kotlin 코드에서 View 객체를 연결시켜준다.
다음 코드는 TextView 객체를 연결시키는 예제 코드입니다.
class MainActivity : AppCompatActivity() {
...
// onCreate()에서 화면이 생성되고 연결해야 하기 때문에 지연생성 사용
private lateinit var textView: TextView
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.textView)
}
}
사용 방법은 그렇게 어렵지 않은 것 같습니다.
하지만 이 방법에는 단점이 있습니다. View 객체를 일일이 다 연결해줘야 하다보니 코드가 굉~~~장히 길어지게 됩니다. 프로젝트만 해보더라도 코드가 굉장히 길어질 수 있습니다. 또한 각각의 요소를 적절한 타입을 명시해줘야 한다는 불편함도 가지고 있었습니다.
이러한 불편함을 JetBrain에서는 이렇게 해결해 주셨습니다.
Kotlin Android Extensions
이름에서 알 수 있는 것처럼 Extension은 Kotlin에서만 사용할 수 있는 방법입니다. 이 방법의 가장 큰 장점은 View 객체를 일일이 연결해주지 않아도 된다는 점입니다. 또 2가지의 장점이 있습니다.
>장점
1) 코드의 간결화
2) 타입문제 해결: 타입을 지정할 필요없이 자동으로 View 객체가 import 됩니다.
3) 재사용성: 내부적인 캐싱을 통해 재사용성을 높일 수 있습니다.
사용법에 대해 알아보겠습니다.
1. build.gradle(app 수준)에 코드를 추가해준다.
plugins {
...
id 'kotlin-android-extensions'
}
이게 끝입니다.
갸꿀?
Gradle에 추가만 해주면 다음과 같이 View 객체를 활용할 수 있습니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.text = "Hello World"
}
}
그냥 xml파일에 있는 id를 그대로 가져와서 활용할 수 있는 것입니다...!!!!
근데 놀라운 점은 Kotlin Android Extensions가 Deprecated 되었습니다.
왜...? 이렇게 간단하고 좋은데 왜....?라고 생각하셨죠?
그 이유는 Extensions의 단점이 있었기 때문입니다.
그럼 그 단점이 무엇인지 보도록 합시다.
1. RecyclerView의 ViewHolder 사용 시 문제점
이 코드가 선언할 필요도 없고 개발자에게도 좋고 프로그램 성능에도 좋은줄 알았더니 사실은 눈속임이였습니다(?)
ReyclerView를 쓰고 Java로 디컴파일한 코드를 보니 여전히 findViewById()
를 쓰고 있는 것이었습니다.
>Kotlin 코드
class SearchAdapter : RecyclerView.Adapter<SearchAdapter.RepositoryHolder>() {
private var items: MutableList<GithubRepo> = mutableListOf()
...
override fun onBindViewHolder(holder: RepositoryHolder, position: Int) {
items[position].let { repo ->
with(holder.itemView) {
tvItemRepositoryName.text = repo.fullName
tvItemRepositoryLanguage.text = if (TextUtils.isEmpty(repo.language))
context.getText(R.string.no_language_specified)
else
repo.language
setOnClickListener { listener?.onItemClick(repo) }
}
}
}
...
}
> Java 디컴파일 코드
public final class SearchAdapter extends Adapter {
...
public void onBindViewHolder(@NotNull SearchAdapter.RepositoryHolder holder, int position) {
Intrinsics.checkParameterIsNotNull(holder, "holder");
Object var3 = this.items.get(position);
GithubRepo repo = (GithubRepo)var3;
View var5 = holder.itemView;
((TextView)var5.findViewById(id.tvItemRepositoryName)).setText((CharSequence)repo.getFullName());
((TextView)var5.findViewById(id.tvItemRepositoryLanguage)).setText(TextUtils.isEmpty((CharSequence)repo.getLanguage())?var5.getContext().getText(2131623973):(CharSequence)repo.getLanguage());
var5.setOnClickListener((OnClickListener)(new SearchAdapter$onBindViewHolder$$inlined$let$lambda$1(repo, this, holder)));
}
...
}
어차피 Kotlin 코드는 컴파일 시에 Java 코드로 변환되는데 findViewById()를 쓰는거면 그냥 '개발자만 편한 코드를 작성할 수 있게 해준다' 정도가 될 수 있겠습니다. 그런데 이 단점 외에 두 가지 단점이 더 있습니다. 아무래도 두 가지 단점때문에 Deprecated가 된게 아닌가 싶네요.
2. 동일한 id를 가지는 뷰가 있을 경우 애매성, 널 안정성 이슈
예를 들어 a.xml 파일에서 textView라는 id를 가진 텍스트뷰가 있고 b.xml 파일에서 textView라는 id를 가진 텍스트뷰가 있을 때를 가정해보겠습니다. 한 액티비티에서 두 textView를 호출한 후 a.xml 파일의 textView를 지워도 액티비티 파일에서 오류가 생기지 않습니다. 이로 인해 충분히 NPE가 생길 수 있는 것이지요.
3. Kotlin에서만 동작
처음 Kotlin Android Extensions를 소개드릴 때 말했던 것처럼 Kotlin에서만 동작하는 것이 문제입니다. 현재도 많은 레거시 코드들은 Java로 되어있는데 안드로이드 퍼스트 코드가 Kotlin일지라도 이렇게 Java한테 매정하게 군다 싶은 것이죠.
그럼 다시 findViewById()로 회귀하는 겁니까...?
다행히도 그렇지 않습니다. Deprecated가 되면 보통 대체할 수 있는 API가 있기 때문에 Deprecated 선언을 해주는데요. 구글에서는 ViewBinding
과 DataBinding
을 대체로 사용할 수 있도록 했습니다. 두 기술에 대해 궁금하시죠? 이건 다음 시간에 포스팅하도록 하겠습니다.(찡긋)
여기까지 읽어주셔서 감사하고 다음 포스팅에서는 ViewBinding에 대해 알아보도록 하겠습니다.
참고
- https://velog.io/@deepblue/Kotlin-Android-Extensions%EC%9D%B4-deprecated%EB%90%9C-%EC%9D%B4%EC%9C%A0
Kotlin-Android-Extensions이 deprecated된 이유
잘가 Kotlin Android Extensions
velog.io
'Android(Kotlin)' 카테고리의 다른 글
[Kotlin] Sealed Class (0) | 2024.02.23 |
---|---|
[Kotlin Android] View 객체 가져오기(2) - ViewBinding (0) | 2022.08.13 |
[Kotlin Android] 반복문 (0) | 2022.06.05 |
[Kotlin Android] MotionLayout을 이용한 Twitter Splash 예제 (0) | 2022.06.04 |
[Kotlin Android] 정적 변수와 메소드 :: Companion Object (0) | 2022.05.30 |