본문 바로가기

Android + Kotlin

[Android Kotlin] 화면간 intent 사용을 쾌적하게(Extension) 해보자.

반응형

안드로이드는 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 도 구현하였으니, 아래 게시물을 확인해주세요.

 

[Android Kotlin] Fragment arguments 를 쾌적하게(Extension) 해보자.

Fragment 사용시 데이터 전달은 arguments 를 이용합니다. arguments는 Bundle 데이터를 사용하기에 데이터를 가져오는 코드를 구현해야 합니다. 단순하고 반복적인 코드들이 파라미터 개수에 따라 코드

heeeju4lov.tistory.com

 

 

 

 

전체 소스 코드는 아래 Github 링크를 확인해 주세요.

 

GitHub - rcbuilders/RemindSampleApp: https://heeeju4lov.tistory.com/ 블로그에서 Android + Kotlin 강좌에서 사용함.

https://heeeju4lov.tistory.com/ 블로그에서 Android + Kotlin 강좌에서 사용함. - GitHub - rcbuilders/RemindSampleApp: https://heeeju4lov.tistory.com/ 블로그에서 Android + Kotlin 강좌에서 사용함.

github.com

 

 

 

위의 코드 구현시에 사용된 inline, crossinline, reified, 제네릭 타입<T> 에 대해서는 아래 게시물 링크를 확인하시면 도움이 되실거예요.

 

 

[Android Kotlin] inline 함수 어떤 경우에 사용하나요?

inline 함수는 어떨때 사용해야 할까요? 알고나면 쉽지만, 막상 사용하려면 어디에 사용해야할지 잘 모르는게 inline 함수 있것 같습니다. (사실, 저도 막~ 잘 알아서 여기저기 사용을 하지는.. 못합

heeeju4lov.tistory.com

 

[Android Kotlin] crossinline, reified 를 알아보자.

지난 inline, noinline 게시글에 이어 crossinline, reified 에 대해 알아보겠습니다. inline, noinline 에 대해서는 아래 링크를 확인해 주세요. [Android Kotlin] inline 함수 어떤 경우에 사용하나요? inline..

heeeju4lov.tistory.com

 

[Android Kotlin] <T>, <K, V> , <*> 너희 정체가 뭐니?

구글링을 하거나, 라이브러리의 소스 등을 보면 , , <*> 이런 코드들이 보입니다. 도대체 뭘까요? 이번 게시물에서는 이 코드들에 대해서 알아보고, 예제를 통해 사용법을 익히고, 친해져보도록

heeeju4lov.tistory.com

 

반응형