Skip to content

Instantly share code, notes, and snippets.

@zhanghai
Last active April 12, 2020 23:23
Show Gist options
  • Save zhanghai/931dec58a7cfef8d19a137adf917b8b3 to your computer and use it in GitHub Desktop.
Save zhanghai/931dec58a7cfef8d19a137adf917b8b3 to your computer and use it in GitHub Desktop.
ParcelableArgs and ParcelableState
/*
* Copyright (c) 2020 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package com.example.yourapplication
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import androidx.annotation.MainThread
import androidx.fragment.app.Fragment
import kotlin.reflect.KClass
interface ParcelableArgs : Parcelable
fun <Args : ParcelableArgs> Bundle.putArgs(args: Args, argsClass: KClass<Args>): Bundle {
putParcelable(argsClass.java.name, args)
return this
}
inline fun <reified Args : ParcelableArgs> Bundle.putArgs(args: Args) = putArgs(args, Args::class)
fun <Args : ParcelableArgs> Args.toBundle(argsClass: KClass<Args>): Bundle =
Bundle().apply { putArgs(this@toBundle, argsClass) }
inline fun <reified Args : ParcelableArgs> Args.toBundle(): Bundle = toBundle(Args::class)
fun <F: Fragment, Args: ParcelableArgs> F.putArgs(args: Args, argsClass: KClass<Args>): F {
val arguments = arguments
if (arguments != null) {
arguments.putArgs(args, argsClass)
} else {
this.arguments = args.toBundle(argsClass)
}
return this
}
inline fun <F: Fragment, reified Args: ParcelableArgs> F.putArgs(args: Args): F =
putArgs(args, Args::class)
fun <Args: ParcelableArgs> Intent.putArgs(args: Args, argsClass: KClass<Args>): Intent =
putExtra(argsClass.java.name, args)
inline fun <reified Args: ParcelableArgs> Intent.putArgs(args: Args) = putArgs(args, Args::class)
fun <Args : ParcelableArgs> Bundle.getArgs(argsClass: KClass<Args>): Args {
classLoader = argsClass.java.classLoader
return getParcelable(argsClass.java.name, argsClass)!!
}
inline fun <reified Args : ParcelableArgs> Bundle.getArgs() = getArgs(Args::class)
@MainThread
inline fun <reified Args : ParcelableArgs> Activity.args() = BundleArgsLazy(Args::class) {
intent.extras ?: throw IllegalStateException("Activity $this has null intent extras")
}
@MainThread
inline fun <reified Args : ParcelableArgs> Fragment.args() = BundleArgsLazy(Args::class) {
arguments ?: throw IllegalStateException("Fragment $this has null arguments")
}
class BundleArgsLazy<Args : ParcelableArgs>(
private val argsClass: KClass<Args>,
private val argumentsProducer: () -> Bundle
) : Lazy<Args> {
private var cached: Args? = null
override val value: Args
get() {
var args = cached
if (args == null) {
args = argumentsProducer().getArgs(argsClass)
cached = args
}
return args
}
override fun isInitialized() = cached != null
}
/*
* Copyright (c) 2020 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package com.example.yourapplication
import android.os.Bundle
import android.os.Parcelable
import kotlin.reflect.KClass
interface ParcelableState : Parcelable
fun <State : ParcelableState> Bundle.putState(state: State) =
putParcelable(state.javaClass.name, state)
fun <State : ParcelableState> Bundle.getState(stateClass: KClass<State>): State {
classLoader = stateClass.java.classLoader
return getParcelable(stateClass.java.name, stateClass)!!
}
inline fun <reified State : ParcelableState> Bundle.getState() = getState(State::class)
/*
* Copyright (c) 2020 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package com.example.yourapplication
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.add
import androidx.fragment.app.commit
import kotlinx.android.parcel.Parcelize
class SampleActivity : AppCompatActivity() {
private val args by args<Args>()
fun addSampleFragment() {
supportFragmentManager.commit {
add<SampleFragment>(android.R.id.content, null, SampleFragment.Args(0, null, Bundle()).toBundle())
}
}
@Parcelize
data class Args(
val intArgument: Int,
val nullableStringArgument: String?,
val parcelableArgument: Bundle
) : ParcelableArgs
}
class SampleFragment : Fragment() {
private val args by args<Args>()
fun startSampleActivity() {
startActivity(
Intent(requireContext(), SampleActivity::class.java).putArgs(SampleActivity.Args(0, null, Bundle()))
)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
val state = savedInstanceState?.getState<State>()
val intValue = state?.intState ?: args.intArgument
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putState(State(false))
}
@Parcelize
data class Args(
val intArgument: Int,
val nullableStringArgument: String?,
val parcelableArgument: Bundle
) : ParcelableArgs
@Parcelize
private data class State(
val intState: Int
) : ParcelableState
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment