View의 생성자
View의 생성자에는 총 4가지가 있습니다.
종류 | 설명 |
View(Context context) | 코드 상에서 View 객체를 생성할때 사용하는 생성자 |
View(Context context, AttributeSet attrs) | XML로부터 View를 객체를 생성(inflate)할때 사용되는 생성자 |
View(Context context, AttributeSet attrs, int defStyleAttr) | XML inflate + theme attribute로 기본 스타일을 적용할때 사용되는 생성자 |
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) | XML inflate + theme attribute와 style attribute로 기본 스타일을 적용할때 사용되는 생성자 |
View | Android Developers
developer.android.com
생성자 오버로딩
하나의 클래스에는 반드시 하나 이상의 생성자가 존재해야 합니다.
프로그래머가 생성자를 구현하지 않은 경우, 컴파일러가 자동으로 기본 생성자 코드를 추가합니다.
기본 생성자는 매개변수가 없고 구현부가 존재하지 않습니다.
생성자에 들어가는 매개변수의 유형과 개수를 다르게 하여 만들고 싶을 때 생성자 오버로딩을 사용합니다.
이를테면, View를 상속받은 클래스를 생성할 때에는 다음 3개의 생성자가 필요합니다.
View(context: Context)
View(context: Context, attrs: AttributeSet)
View(context: Context, attrs: AttributeSet, defStyleAttr: Int)
그러나 아래처럼 저 중 하나만 상속받아 사용하면 예상치 못한 오류가 발생합니다.
내부적으로 xml을 inflate해주는 과정에서 3개의 constructor가 모두 실행되기 때문입니다.
class CustomView(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View (context, attrs, defStyleAttr)
따라서, 정상적으로 작동하는 코드를 작성하려면 각각의 생성자를 모두 구현해야 합니다.
하지만 코틀린은 @JvmOverloads라는 어노테이션을 통해 더욱 간결한 생성자 오버로딩을 지원합니다.
@JvmOverloads은 컴파일러에게 인수를 default 값으로 대체하는 생성자를 만들도록 지시합니다.
@JvmOverloads
@JvmOverloads는 생성자 오버로딩을 자동으로 생성해 주는 어노테이션입니다.
이를 통해 여러 개의 생성자를 상속받는 번거로움이 줄어들고 보일러플레이트 코드를 최소화할 수 있습니다.
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr)
해당 코드를 디컴파일해보면 실제로 다음과 같이 생성자들이 모두 생성됩니다.
public CustomView(@NotNull Context context)
public CustomView(@NotNull Context context, @Nullable AttributeSet attrs)
public CustomView(@NotNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr)
public CustomView(Context var1, AttributeSet var2, int var3, int var4, DefaultConstructorMarker var5)
@JvmOverloads 사용 시 주의할 점
xml로 View를 inflate할 때 두번째 생성자가 사용되는데 이 과정에서 세번째 생성자가 호출됩니다.
여기서 View들은 attr.buttonStyle, attr.editTextStyle 등으로 custom한 style을 넣어줄 수 있습니다.
하지만 @JvmOverloads을 사용하여 CustomView를 만들 경우에 defStyleAttr 값에 확장할 View의 기본 Style 값이 전달되는 것이 아니라 @JvmOverloads 생성자에 있는 기본값으로 대체되어 예상과 다른 작동이 생길 우려가 있습니다.
// 원래 의도
constructor(context: Context, attrs: AttributeSet?)
: this(context, attrs, android.R.attr.buttonStyle) { }
// @JvmOverloads 사용 시 default 값인 0으로 대체
constructor(context: Context, attrs: AttributeSet?)
: this(context, attrs, 0) { }
이럴 경우에는 @JvmOverloads을 사용하지 않고 constructor를 직접 작성해 super을 사용하면 됩니다.
class CustomButton: AppCompatButton {
constructor(context: Context) : super(context) { }
constructor(context: Context, attrs: AttributeSet?)
: super(context, attrs) { }
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
: super(context, attrs, defStyleAttr) { }
}
'안드로이드 > 개념' 카테고리의 다른 글
[Android] ViewBinding과 DataBinding (0) | 2023.10.08 |
---|---|
[Android] Touch (0) | 2023.10.06 |
[Android] Broadcast Receiver (0) | 2023.08.01 |
[Android] Service (0) | 2023.08.01 |
[Android] sealed class (0) | 2023.07.30 |