안드로이드는 intent를 이용하여 화면간 데이터를 전달합니다.
이렇게 자주 사용하는 intent인데, 오랜만에 특정 화면을 호출할때면 어떤 데이터를 어떤 키로 보내면 되는지.. intent를 받는 화면은 데이터를 받는 유사한 코드를 계속 만들어야 합니다.
살짝(?) 지겹고 귀찮은 일이 아닐수 없습니다.
그래서, 좀더 쾌적하게 할수 있는 방법이 없을까를 조금.. 다소(?).. 고민을 해본 끝에..
(주관적으로) 기존보다는 조금더 낫다고 생각되는 방법으로 구현하여 사용중에 있습니다.
이 게시물에서는 저의 방식에 대해서 공유 드립니다.(보시고 괜찮으신 분들만 사용해주세요..)
Activity에서 받아야 하는 데이터는 정해져 있기때문에 호출하는 쪽에 "요런~요런 데이터를 보내줘~" 라고 가이드를 주면 좀더 나을것이라 생각하였습니다.
그래서, 아래 코드와 같이 Activity class에 createInten()함수 파라미터로 필요한 데이터를 받고, intent를 반환하도록 하였습니다.
장점으로는 호출하는 쪽에서 intent extra key를 알필요가 없이, createIntent()함수의 파라미터만 알면 되기때문에, 공동 개발시나 오랜 시간이 지나서 개발시에도 좀더 소스 분석이 빨라질 것으로 생각됩니다.
companion object {
private const val INTENT_EXTRA_KEY_TEXT = "intent.extra.TEXT"
private const val INTENT_EXTRA_KEY_NUMBER = "intent.extra.NUMBER"
private const val INTENT_EXTRA_KEY_IS_OK = "intent.extra.is.OK"
private const val INTENT_EXTRA_KEY_DATA = "intent.extra.DATA"
fun createIntent(
context: Context,
text: String? = null,
number: Int? = null,
isOk: Boolean? = null,
data: IntentData? = null
): Intent {
return Intent(context, IntentExampleActivity::class.java).apply {
text?.let { putExtra(INTENT_EXTRA_KEY_TEXT, it) }
number?.let { putExtra(INTENT_EXTRA_KEY_NUMBER, it) }
isOk?.let { putExtra(INTENT_EXTRA_KEY_IS_OK, it) }
data?.let { putExtra(INTENT_EXTRA_KEY_DATA, it as Serializable) }
}
}
}
이제 intent를 수신하는 부분은 어떻게하면 쾌적하게 될까요?
일반적으로는 아래의 코드와 같이, 필요한 Activity에서 intent extra get 을 하는 구현을 했습니다.
/**
* 일반적인 intent data get 방법
*/
intent?.getStringExtra(INTENT_EXTRA_KEY_TEXT)?.let {
println("text is $it")
}
intent?.getIntExtra(INTENT_EXTRA_KEY_NUMBER, -1)?.let {
println("number is $it")
}
intent?.getBooleanExtra(INTENT_EXTRA_KEY_IS_OK, false)?.let {
println("isOk is $it")
}
intent?.getSerializableExtra(INTENT_EXTRA_KEY_DATA)?.let {
println("isOk is ${it as IntentData}")
}
Activity마다 유사한 코드로 기본적으로 코드 라인을 차지하게되어 좀더 짧게 하고자 했습니다.
그래서, Extension을 이용하여 intent extra data를 가져오는 함수를 만들었습니다.
/**
* private val a: Int by extraParams('key', -1)
*/
inline fun<reified T: Any> Activity.extraParams(key: String, defaultValue: T) = lazy {
val result = when(defaultValue) {
is Boolean -> intent.getBooleanExtra(key, defaultValue)
is Int -> intent.getIntExtra(key, defaultValue)
is CharSequence -> intent.getStringExtra(key)
is Serializable -> intent.getSerializableExtra(key)
else -> throw IllegalArgumentException("IllegalArgument value type [${defaultValue.javaClass}] / key [$key]")
} as? T
return@lazy result ?: defaultValue
}
/**
* private val a: Serializable by extraParams('key') { as Serializable() }
*/
inline fun<reified T: Any> Activity.extraParams(key: String, crossinline defaultValue: () -> T? = { null }) = lazy {
val objectType = T::class.javaObjectType
val result = when {
Serializable::class.java.isAssignableFrom(objectType) -> intent.getSerializableExtra(key) ?: defaultValue.invoke()
else -> throw IllegalArgumentException("Illegal value type [${objectType}] / key [$key]")
} as? T
return@lazy result
}
/**
* private val a: Serializable by extraParams('key') // Not null
*/
inline fun<reified T: Any> Activity.extraParamsNotNull(key: String) = lazy<T> {
val objectType = T::class.javaObjectType
val result = when {
Serializable::class.java.isAssignableFrom(objectType) -> intent.getSerializableExtra(key)
else -> throw IllegalArgumentException("Illegal value type [${objectType}] / key [$key]")
} as T
return@lazy result
}
데이터를 저장할 변수의 타입과 key를 이용하여 intent의 데이터를 가져오도록 구현하였습니다.
사용은 아래 코드와 같이 사용할 수 있습니다.
private val text: String? by extraParams(INTENT_EXTRA_KEY_TEXT)
private val number: Int? by extraParams(INTENT_EXTRA_KEY_NUMBER, -1)
private val isOk: Boolean? by extraParams(INTENT_EXTRA_KEY_IS_OK, false)
private val data: IntentData? by extraParams(INTENT_EXTRA_KEY_DATA)
기존에 intent extra get 하던 코드가 모두 사려져, 코드가 짧아지고 깔끔해졌다고.. 저 혼자 자평을 하고 있습니다.ㅎㅎ
결과를 보시면 기존의 intent extra get 으로 호출할때와 동일한 결과가 나오는 것을 확인하실 수 있습니다.
동일한 방식으로 Fragment arguments 도 구현하였으니, 아래 게시물을 확인해주세요.
전체 소스 코드는 아래 Github 링크를 확인해 주세요.
위의 코드 구현시에 사용된 inline, crossinline, reified, 제네릭 타입<T> 에 대해서는 아래 게시물 링크를 확인하시면 도움이 되실거예요.
'Android + Kotlin' 카테고리의 다른 글
[Android Kotlin] 안전하게 Enum 타입 사용하기 (0) | 2022.01.24 |
---|---|
[Android Kotlin] Fragment arguments 를 쾌적하게(Extension) 해보자. (0) | 2022.01.21 |
[Android Kotlin] crossinline, reified 를 알아보자. (0) | 2022.01.21 |
[Android Kotlin] inline 함수 어떤 경우에 사용하나요? (0) | 2022.01.20 |
[Android Kotlin] <T>, <K, V> , <*> 너희 정체가 뭐니? (0) | 2022.01.13 |