Bundle¶
BundleSpec to use Bundle with property syntax for Intent extras
and more.
Supported platforms: Android.
Setup¶
If you want to use this dependency without using one of the fun packs,
you can use Splitties.bundle, provided you have refreshVersions added to the project.
For reference, the maven coordinates of this module are com.louiscad.splitties:splitties-bundle.
Non-exhaustive list of use cases¶
Intentextras of Activities, BroadcastReceivers, Services, etc.- Instance state of Activities, Fragments and Views.
Can be used for Activity extras, but also in Service extras,
BroadcastReceiver and other parts where an Intent or a Bundle is used.
Usage¶
For Activity extras¶
- Let's say you have an
Activitysubclass namedYourActivity. - In
YourActivity, add a nestedobjectnamedExtrasSpec. - Make it extend
BundleSpec. - For each required
Intentextra you need, inExtrasSpec, add avarproperty with explicit non null type, delegatedby bundle(). - For each optional
Intentextra you need, still inExtrasSpec, add avarproperty with either and explicit nullable type, delegatedby bundleOrNull(), or with a non null type, delegatedby bundleOrDefault(…)orby bundleOrElse { … }. - When setting up the
Intentto start yourActivity, callputExtras(YourActivity.ExtrasSpec) { … }on it, setting values on theExtrasSpecproperties in the lambda. - From
YourActivity, callwithExtras(ExtrasSpec) { … }to get the extras as properties from the lambda (the result of the call is the result of the lambda).
Other usages¶
Only Activity has a withExtras(…) { … } extension, but you
can use with(…) { … } extension on any Bundle and any Intent extras.
The putExtras(…) { … } extension works on any Intent, Activity or not.
See the examples below.
Important details¶
See the implementation of the put(…) extension on Bundle to check all
the supported types (it is likely to suit your needs).
You may only access the delegated properties of a BundleSpec subclass
inside the withExtras(…) { … } lambda or inside the
someBundle.with(…) { … } lambda. If you violate this rule, an
IllegalStateException will be thrown.
The implementation has been optimized for efficiency. The delegates under
bundle() and bundleOrNull() are singletons and are shared for all
properties app-wide.
The versions that accept a key or a default value can't be singletons, but since
you're likely using them in object backed specs, they are instantiated only
once per property, having a minimal memory impact (especially when compared to
the cost of data serialization in Bundles).
Examples¶
Extras in an Activity¶
class DemoActivity : AppCompatActivity() {
object ExtrasSpec : BundleSpec() {
var userName: String by bundle() // Required extra
var showGreetingToast by bundleOrDefault(false) // Optional extra, defaults to false
var optionalExtra: String? by bundleOrNull() // Optional extra
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
withExtras(ExtrasSpec) { // Populates ExtrasSpec with actual extras
if (showGreetingToast) toast(android.R.string.ok)
optionalExtras?.forEach {
Timber.i("Character from optional extra: $it")
}
}
restOfYourCode()
}
}
class StartDemoActivity : AppCompatActivity() {
private fun someFunction(name: String, isUserPolite: Boolean = false) {
startActivity(Intent(this, DemoActivity::class.java).apply {
putExtras(DemoActivity.ExtrasSpec) {
userName = name
showGreetingToast = isUserPolite
}
})
}
}
Extras in a BroadcastReceiver¶
class AirplaneModeReceiver : BroadcastReceiver() {
object ExtrasSpec : BundleSpec() {
var isAirplaneModeOn: Boolean by bundle("state")
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_AIRPLANE_MODE_CHANGED) return
val isAirplaneModeOn = intent.extras.with(ExtrasSpec) { isAirplaneModeOn }
handleAirplaneMode(isAirplaneModeOn)
}
}
Instance State in an Activity¶
class DemoActivity : AppCompatActivity() {
private object InstanceStateSpec : BundleSpec() {
var startTime: Long by bundle()
}
private var startTimestamp = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startTimestamp = savedInstanceState?.with(InstanceStateSpec) {
startTime
} ?: System.currentTimeMillis()
restOfYourCode()
}
override fun onSaveInstanceState(outState: Bundle) {
outState.with(InstanceStateSpec) {
startTime = startTimestamp
}
super.onSaveInstanceState(outState)
}
}