728x90
반응형
이번 포스팅은 Activity를 start하거나 Fragment를 보여주는 코드를 어떻게 하면 간단하게 보여줄 수 있는지 소개하고자 합니다.
Activity
기존 스타일
// in Activity
val intent = Intent(this, DestinationActivity::class.java)
intent.putExtra("key1", "value1")
intent.putExtra("key2", "value2")
startActivity(intent)
// in Fragment
val intent = Intent(requireContext(), DestinationActivity::class.java)
intent.putExtra("key1", "value1")
intent.putExtra("key2", "value2")
startActivity(intent)
Companion
ActivityTemplate.kt
abstract class ActivityTemplate<T : Activity> {
private val clazz: Class<*>
get() = ((this.javaClass.genericSuperclass as ParameterizedType?)?.actualTypeArguments
?.get(0) as Class<*>)
fun start(
context: Context,
vararg param: Pair<String, Any?>,
intentAction: Intent.() -> Unit = {}
) {
context.startActivity(createIntent(context, *param).apply(intentAction))
}
fun createIntent(context: Context, vararg param: Pair<String, Any?>) =
Intent(context, clazz).apply { putExtras(bundleOf(*param)) }
}
DestinationActivity.kt
class DestinationActivity : AppCompatActivity(R.layout.activity_destination) {
companion object : ActivityTemplate<DestinationActivity>()
}
사용하기
// in Activity
DestinationActivity.start(this, "key1" to "value1", "key2" to "value2")
// in Fragment
DestinationActivity.start(requireContext(), "key1" to "value1", "key2" to "value2")
기존 스타일보다 사용하기는 편해졌지만 Activity마다 companion object를 만들고 ActivityTemplate을 상속해야 하는 작은 불편함이 있습니다.
Extension function
IntentExtension.kt
fun <T> createIntent(
context: Context,
clazz: Class<out T>,
params: Array<out Pair<String, Any?>>
) = Intent(context, clazz).apply { putExtras(bundleOf(*params)) }
ContextExtension.kt
inline fun <reified T : Activity> Context.startActivity(
vararg param: Pair<String, Any?>,
intentAction: Intent.() -> Unit = {}
) {
val intent = createIntent(this, T::class.java, param).apply(intentAction)
startActivity(intent)
}
FragmentExtension.kt
inline fun <reified T : Activity> Fragment.startActivity(
vararg param: Pair<String, Any?>,
intentAction: Intent.() -> Unit = {}
) {
val intent = createIntent(requireContext(), T::class.java, param).apply(intentAction)
startActivity(intent)
}
사용하기
// in Activity
startActivity<DestinationActivity>("key1" to "value1", "key2" to "value2")
// in Fragment
startActivity<DestinationActivity>("key1" to "value1", "key2" to "value2")
기존 스타일과 비슷한 형태지만 Intent를 만들 필요 없이 사용 할 수 있고 Companion 스타일처럼 추가 작업을 할 필요 없어서 간단하게 사용 할 수 있습니다.
Fragment
기존 스타일
supportFragmentManager.findFragmentByTag(tag)
?: DestinationFragment().also { newFragment ->
val bundle = Bundle()
bundle.putString("key1", "value1")
bundle.putString("key2", "value2")
newFragment.arguments = bundle
supportFragmentManager.beginTransaction()
.replace(R.id.fl_container, newFragment, tag)
.commit()
}
Companion
FragmentTemplate.kt
@Suppress("UNCHECKED_CAST")
abstract class FragmentTemplate<out T : Fragment> {
private val clazz: Class<*>
get() = ((this.javaClass.genericSuperclass as ParameterizedType?)?.actualTypeArguments
?.get(0) as Class<*>)
fun replace(
fragmentManager: FragmentManager,
@IdRes containerViewId: Int,
vararg param: Pair<String, Any?>,
tag: String = clazz.simpleName
) {
find(fragmentManager, tag) ?: newInstance(*param).let { newFragment ->
fragmentManager.beginTransaction()
.replace(containerViewId, newFragment, tag)
.commitAllowingStateLoss()
}
}
fun find(fragmentManager: FragmentManager, tag: String = clazz.simpleName) =
fragmentManager.findFragmentByTag(tag) as? T
fun newInstance(vararg param: Pair<String, Any?>) =
(clazz.newInstance() as Fragment).apply { arguments = bundleOf(*param) } as T
}
DestinationFragment.kt
class DestinationFragment : Fragment(R.layout.destination) {
companion object : FragmentTemplate<DestinationFragment>()
}
사용하기
// in Activity
DestinationFragment.replace(
supportFragmentManager,
R.id.fl_container,
"key1" to "value1",
"key2" to "value2"
)
// in Fragment
DestinationFragment.replace(
fragmentManager,
R.id.fl_container,
"key1" to "value1",
"key2" to "value2"
)
기존 스타일보다 사용하기는 편해졌지만 Fragment마다 companion object를 만들고 FragmentTemplate을 상속해야 하는 작은 불편함이 있습니다.
Extension function
FragmentActivityExtension.kt
inline fun <reified T : Fragment> FragmentActivity.replaceFragment(
@IdRes containerViewId: Int,
vararg param: Pair<String, Any?>,
tag: String = T::class.java.simpleName
) {
findFragment() ?: T::class.java.newInstance().also { newFragment ->
newFragment.arguments = bundleOf(*param)
supportFragmentManager.beginTransaction()
.replace(containerViewId, newFragment, tag)
.commitAllowingStateLoss()
}
}
inline fun <reified T : Fragment> FragmentActivity.findFragment(tag: String = T::class.java.simpleName): T? {
return supportFragmentManager.findFragmentByTag(tag) as? T
}
FragmentExtension.kt
inline fun <reified T : Fragment> Fragment.replaceFragment(
@IdRes containerViewId: Int,
vararg param: Pair<String, Any?>,
tag: String = T::class.java.simpleName
) {
findFragment() ?: T::class.java.newInstance().also { newFragment ->
newFragment.arguments = bundleOf(*param)
childFragmentManager.beginTransaction()
.replace(containerViewId, newFragment, tag)
.commitAllowingStateLoss()
}
}
inline fun <reified T : Fragment> Fragment.findFragment(tag: String = T::class.java.simpleName): T? {
return childFragmentManager.findFragmentByTag(tag) as? T
}
사용하기
// in Activity
replaceFragment<DestinationFragment>(
R.id.fl_container,
"key1" to "value1",
"key2" to "value2"
)
// in Fragment
replaceFragment<DestinationFragment>(
R.id.fl_container,
"key1" to "value1",
"key2" to "value2"
)
Activity의 Extension function과 비슷한 형태이고 Companion 스타일처럼 추가 작업을 할 필요 없어서 간단하게 사용 할 수 있습니다.
참고자료
(Android) bundleOf로 데이터 편하게 전달하기
이번 포스팅은 bundleOf()를 사용해서 Activity나 Fragment에 데이터를 더욱 더 쉽게 전달하는 방법에 대해 소개 합니다.SetupbundleOf()함수는 Android KTX중에 core-ktx에 있는 함수 입니다.그래서 사용하기 전
dino-dev.tistory.com
블로그 글에 대해 궁금한 점이 있다면 아래 카카오톡 오픈채팅에 들어와서 질문해주세요
Android Kotlin Compose QnA
open.kakao.com
728x90
반응형
'개발 > 안드로이드' 카테고리의 다른 글
(Android) bundleOf로 데이터 편하게 전달하기 (2) | 2025.05.09 |
---|---|
(Android) Dynamic App Icon (0) | 2024.02.21 |
(Android) 네이버/카카오 API 키 안전하게 관리하기 (0) | 2024.01.08 |