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¶
Intent
extras 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
Activity
subclass namedYourActivity
. - In
YourActivity
, add a nestedobject
namedExtrasSpec
. - Make it extend
BundleSpec
. - For each required
Intent
extra you need, inExtrasSpec
, add avar
property with explicit non null type, delegatedby bundle()
. - For each optional
Intent
extra you need, still inExtrasSpec
, add avar
property with either and explicit nullable type, delegatedby bundleOrNull()
, or with a non null type, delegatedby bundleOrDefault(…)
orby bundleOrElse { … }
. - When setting up the
Intent
to start yourActivity
, callputExtras(YourActivity.ExtrasSpec) { … }
on it, setting values on theExtrasSpec
properties 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)
}
}