반응형
Fragment 사용시 데이터 전달은 arguments 를 이용합니다.
arguments는 Bundle 데이터를 사용하기에 데이터를 가져오는 코드를 구현해야 합니다.
단순하고 반복적인 코드들이 파라미터 개수에 따라 코드량이 늘어나게 되어, 가독성이 조금이나마 떨어지기에 개션을 해보고자 합니다.
이전 intent 데이터를 개선한 것과 동일한 방법으로 구현하였습니다.
일반적으로 Fragment 에서 arguments를 사용하는 경우, 아래 코드와 같이 데이터를 가져옵니다.
/**
* 일반적인 fragment arguments data get 방법
*/
arguments?.getString(INTENT_EXTRA_KEY_TEXT)?.let {
println("text is $it")
}
arguments?.getInt(INTENT_EXTRA_KEY_NUMBER)?.let {
println("number is $it")
}
arguments?.getBoolean(INTENT_EXTRA_KEY_IS_OK)?.let {
println("isOK is $it")
}
arguments?.getSerializable(INTENT_EXTRA_KEY_DATA)?.let {
println("isOK is ${it as IntentData}")
}
단순하고 중복된 코드로 보기만해도 숨이 턱~ 막히는 느낌입니다.
이를 좀더 쾌적하게 수정하고자 했습니다.
Fragment Extension으로 변수 사용시 자동으로 가져오도록 하였습니다.
inline fun<reified T: Any> Fragment.argumentParams(key: String, defaultValue: T) = lazy {
val result = when(defaultValue) {
is Boolean -> arguments?.getBoolean(key, defaultValue)
is Int -> arguments?.getInt(key, defaultValue)
is CharSequence -> arguments?.getString(key)
is Serializable -> arguments?.getSerializable(key) ?: defaultValue
else -> throw IllegalArgumentException("IllegalArgument value type [${defaultValue.javaClass}] / key [$key]")
} as? T
return@lazy result ?: defaultValue
}
inline fun<reified T: Any> Fragment.argumentParams(key: String, crossinline defaultValue: () -> T? = { null }) = lazy {
val objectType = T::class.javaObjectType
val result = when {
Serializable::class.java.isAssignableFrom(objectType) -> arguments?.getSerializable(key) ?: defaultValue.invoke()
else -> throw IllegalArgumentException("Illegal value type [${objectType}] / key [$key]")
} as? T
return@lazy result
}
inline fun<reified T: Any> Fragment.argumentParamsNotNull(key: String) = lazy<T> {
val objectType = T::class.javaObjectType
val result = when {
Serializable::class.java.isAssignableFrom(objectType) -> arguments?.getSerializable(key)
else -> throw IllegalArgumentException("Illegal value type [${objectType}] / key [$key]")
} as T
return@lazy result
}
사용 방법은 변수 선언하는 부분에 데이터가 셋팅되도록 구현하면 됩니다.
private val text: String? by argumentParams(INTENT_EXTRA_KEY_TEXT)
private val number: Int? by argumentParams(INTENT_EXTRA_KEY_NUMBER, -1)
private val isOk: Boolean? by argumentParams(INTENT_EXTRA_KEY_IS_OK, false)
private val data: IntentData? by argumentParams(INTENT_EXTRA_KEY_DATA)
위의 코드는 해당 변수(text, number, ...) 를 사용시 자동으로 arguments에서 데이터를 가져오도록 구현되었습니다.
Extension으로 구현된 만큼, 모든 Fragment 클래스에서 사용 가능합니다.
결과는 아래와 같이 일반적인 방법과 동일한 결과를 보실수 있으십니다.
전체 소스 코드는 아래 Github 링크를 확인해 주세요.
위의 코드 구현시에 사용된 inline, crossinline, reified, 제네릭 타입<T> 에 대해서는 아래 게시물 링크를 확인하시면 도움이 되실거예요.
반응형
'Android + Kotlin' 카테고리의 다른 글
[Android Kotlin] TransactionTooLargeException 해결 방법 (0) | 2022.01.25 |
---|---|
[Android Kotlin] 안전하게 Enum 타입 사용하기 (0) | 2022.01.24 |
[Android Kotlin] 화면간 intent 사용을 쾌적하게(Extension) 해보자. (0) | 2022.01.21 |
[Android Kotlin] crossinline, reified 를 알아보자. (0) | 2022.01.21 |
[Android Kotlin] inline 함수 어떤 경우에 사용하나요? (0) | 2022.01.20 |