본문 바로가기
개발 공부 기록하기/- Android

[Android] Intent, Bundle, SavedStateHandle 객체 쉽게 전달하기.

by soulduse 2023. 11. 26.
반응형

 

Intent, Bundle, SavedStateHandle로 다양한 데이터를 넘겨받는데 특히 객체를 넘겨받을 경우가 많다.

 

여러가지 방법이 있겠지만 주로 사용하는 방법은 객체를 Json으로 변환한 뒤 다시 받는 쪽에서는 Json을 객체에 매핑시켜 데이터를 가져오는 구조로 주로 사용을 했다.

 

AS-IS

하지만 이게 매번 하려니 여간 번거로운게 아니다 하나 예시를 보자.

val dataDTO = DataDTO(....)
val intent = Intent(context, InfoActivity::class.java).apply {
    val jsonAdapter = moshi.adapter(DataDTO::class.java)
    this.putExtra("test", jsonAdapter.toJson(dataDTO))
}
context.startActivity(intent)

데이터를 Json으로 변환하고 다시 객체로 변환하기위에 Moshi를 사용한다면 위와 같은 코드를 사용하게 될 것이다.

 

그리고 받으려면 마찬가지로 아래와 같이 Json을 다시 객체로 변환하는 과정을 거쳐야 한다.

val dataDTOJson = intent.getStringExtra("test") ?: return
val jsonAdapter = moshi.adapter(DataDTO::class.java)
val dataDTO = jsonAdapter.fromJson(dataDTOJson) ?: return

 


우선 SIMPLE IS BEST를 사랑하는 나는 단순히 데이터를 넘기는데 너무 복잡하다고 생각이 든다.

 

단순화 하기위해 유틸성 확장함수를 만들었고 어떻게 사용할수 있나 확인해보자

 

TO-BE

보내는 부분 (강화 +1)

val dataDTO = DataDTO(....)
val intent = Intent(context, InfoActivity::class.java).apply {
    putAsJson("test", dataDTO)
}

 

어떤가? 여기서 한번더 단순화 해보면 다음과 같이 사용할 수 있다.

보내는 부분 (강화 +2)

val dataDTO = DataDTO(....)
context.start<InfoActivity> {
    putAsJson("test", dataDTO)
}

 

받을때

val dataDTO = intent.getAsObject<DataDTO>("test")

 

어떻게 했나?

위처럼 단순화하기 위해 생성한 확장 함수는 다음과 같다.

Intent, Bundle, SavedStateHandle 모두 커버가능하며 정말 단순화하여 객체를 전달 할 수 있다. Gson 사용을 선호하는 분이라면 MoshiProvider 부분만 Gson으로 적절히 변경해서 사용하면 되겠다.

import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.SavedStateHandle
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory

object MoshiProvider {
    val instance: Moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()
}

// Bundle에 객체를 JSON으로 직렬화하여 저장합니다.
inline fun <reified T> Bundle.putAsJson(key: String, value: T) {
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    this.putString(key, jsonAdapter.toJson(value))
}

// Bundle에서 JSON 문자열을 객체로 역직렬화하여 가져옵니다.
inline fun <reified T> Bundle.getAsObject(key: String): T? {
    val json = this.getString(key) ?: return null
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    return jsonAdapter.fromJson(json)
}

// Intent에 객체를 JSON으로 직렬화하여 저장합니다.
inline fun <reified T> Intent.putAsJson(key: String, value: T) {
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    this.putExtra(key, jsonAdapter.toJson(value))
}

// Intent에서 JSON 문자열을 객체로 역직렬화하여 가져옵니다.
inline fun <reified T> Intent.getAsObject(key: String): T? {
    val json = this.getStringExtra(key) ?: return null
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    return jsonAdapter.fromJson(json)
}

// SavedStateHandle에 객체를 JSON으로 직렬화하여 저장합니다.
inline fun <reified T> SavedStateHandle.putAsJson(key: String, value: T) {
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    this[key] = jsonAdapter.toJson(value)
}

// SavedStateHandle에서 JSON 문자열을 객체로 역직렬화하여 가져옵니다.
inline fun <reified T> SavedStateHandle.getAsObject(key: String): T? {
    val json = this.get<String>(key)
    val jsonAdapter = MoshiProvider.instance.adapter(T::class.java)
    return json?.let { jsonAdapter.fromJson(it) }
}

 

그리고 추가로 Intent를 단순하게 사용하려면 아래 확장함수를 사용하면 된다.

Context, Fragment, Activity만 가지고 있다면 손쉽게 startActivity를 할 수 있다.

inline fun <reified A : Activity> Context.start(configIntent: Intent.() -> Unit = {}) {
    startActivity(Intent(this, A::class.java).apply(configIntent))
}

inline fun <reified A : Activity> Activity.start(configIntent: Intent.() -> Unit = {}) {
    startActivity(Intent(this, A::class.java).apply(configIntent))
}

inline fun <reified A : Activity> Fragment.start(configIntent: Intent.() -> Unit = {}) {
    startActivity(Intent(this.context, A::class.java).apply(configIntent))
}

 

복잡한건 심플하게, 최대한 단순하게 사용해보자.

반응형