项目作者: Takhion

项目描述 :
Kotlin property delegates to manage Android Intent and Bundle extras
高级语言: Kotlin
项目地址: git://github.com/Takhion/android-extras-delegates.git
创建时间: 2017-02-05T20:01:43Z
项目社区:https://github.com/Takhion/android-extras-delegates

开源协议:MIT License

下载


Android Extras Delegates

Contains a collection of Kotlin property delegates to manage Android Intent and Bundle extras.

See @workingkills/you-wont-believe-this-one-weird-trick-to-handle-android-intent-extras-with-kotlin-845ecf09e0e9">this article for more information.

Usage

Create an object (anywhere, although by convention it’s inside an Activity) and declare inside it some delegated extension properties over Intent or Bundle (all types are supported):

  1. package com.example
  2. class SomeActivity : Activity() {
  3. object IntentOptions {
  4. var Intent.someExtra by IntentExtra.String()
  5. }
  6. }

IntentExtra and BundleExtra are two empty object which serve as containers for all delegates.

If not specified, the name of the extra will be the fully qualified name of the containing class, followed by the property name (in the example: "com.example.SomeActivity.IntentOptions::someExtra").
It is also possible to specify a custom prefix instead of the fully qualified name of the class, which is useful when creating nested delegates (see below).

If a default value is not specified, the returning type will be nullable.

To use a delegate, you need to bring the container in which it’s defined in the current scope, like so:

  1. fun test(intent: Intent) {
  2. with(SomeActivity.IntentOptions) {
  3. val someExtraValue = intent.someExtra
  4. intent.someExtra = "hello"
  5. }
  6. }

Activity Companion

Optionally, you can use the provided ActivityCompanion (or SimpleActivityCompanion if you don’t have any “intent options”) to aid in creating intents for an Activity:

  1. class SomeActivity : Activity() {
  2. companion object : ActivityCompanion<IntentOptions>(IntentOptions, SomeActivity::class)
  3. object IntentOptions {
  4. var Intent.someExtra by IntentExtra.String()
  5. }
  6. fun test() {
  7. val someExtraValue = intent.options { it.someExtra }
  8. }
  9. }
  10. fun test(context: Context) {
  11. SomeActivity.start(context) {
  12. it.someExtra = "hello"
  13. }
  14. // or
  15. val someActivityIntent = SomeActivity.intent(context) {
  16. it.someExtra = "hello"
  17. }
  18. }

Custom types

Creating your own delegates is simple, as all building blocks are already provided.

For example to create a LocalDate (from Joda-Time), persisted as a String in an Intent:

  1. import me.eugeniomarletti.extras.intent.IntentExtra
  2. import me.eugeniomarletti.extras.intent.base.String
  3. import org.joda.time.LocalDate
  4. fun IntentExtra.LocalDate(name: String? = null, customPrefix: String? = null) =
  5. String(
  6. reader = { it?.let(LocalDate::parse) },
  7. writer = { it?.toString() },
  8. name = name,
  9. customPrefix = customPrefix)

Or in a Bundle:

  1. import me.eugeniomarletti.extras.bundle.BundleExtra
  2. import me.eugeniomarletti.extras.bundle.base.String
  3. import org.joda.time.LocalDate
  4. fun BundleExtra.LocalDate(name: String? = null, customPrefix: String? = null) =
  5. String(
  6. reader = { it?.let(LocalDate::parse) },
  7. writer = { it?.toString() },
  8. name = name,
  9. customPrefix = customPrefix)

The reader takes the persisted value in and outputs the custom type, while the writer does the opposite.

By defining the custom extensions on IntentExtra/BundleExtra, they will show up together with the basic types in the IDE autocomplete.

Nested types

There are cases when a type is composed of multiple simpler types, like the following example:

  1. data class User(val id: Long, val email: String, val birthDay: LocalDate)

It’s possible to compose multiple delegates to create a single “super delegate” that can read/write such a type:

  1. import android.content.Intent
  2. import me.eugeniomarletti.extras.DelegateProvider
  3. import me.eugeniomarletti.extras.defaultDelegateName
  4. import me.eugeniomarletti.extras.intent.IntentExtra
  5. import me.eugeniomarletti.extras.intent.base.Long
  6. import me.eugeniomarletti.extras.intent.base.String
  7. import kotlin.properties.ReadWriteProperty
  8. import kotlin.reflect.KProperty
  9. fun IntentExtra.User(
  10. idName: String? = null,
  11. emailName: String? = null,
  12. birthdayName: String? = null,
  13. customPrefix: String? = null)
  14. =
  15. object : DelegateProvider<ReadWriteProperty<Intent, User?>> {
  16. override fun provideDelegate(thisRef: Any?, property: KProperty<*>) =
  17. object : ReadWriteProperty<Intent, User?> {
  18. private val namePrefix = property.defaultDelegateName(customPrefix)
  19. private var Intent.id by IntentExtra.Long(name = idName, customPrefix = namePrefix)
  20. private var Intent.email by IntentExtra.String(name = emailName, customPrefix = namePrefix)
  21. private var Intent.birthday by IntentExtra.LocalDate(name = birthdayName, customPrefix = namePrefix)
  22. override operator fun getValue(thisRef: Intent, property: KProperty<*>): User? {
  23. val id = thisRef.id ?: return null
  24. val email = thisRef.email ?: return null
  25. val birthday = thisRef.birthday ?: return null
  26. return User(id, email, birthday)
  27. }
  28. override operator fun setValue(thisRef: Intent, property: KProperty<*>, value: User?) {
  29. thisRef.id = value?.id
  30. thisRef.email = value?.email
  31. thisRef.birthday = value?.birthDay
  32. }
  33. }
  34. }

An example usage could be:

  1. package com.example
  2. object IntentOptions {
  3. var Intent.currentUser by IntentExtra.User()
  4. }

This will read/write 3 extras:

  • com.example.IntentOptions::currentUser::id with type Long
  • com.example.IntentOptions::currentUser::email with type String
  • com.example.IntentOptions::currentUser::birthday with type LocalDate (which is actually String)

Note that this is made possible by passing a custom prefix for the nested property names, which is going to be the default delegate name for the “super delegate” (in this case com.example.IntentOptions::currentUser).

The extra names can also be specified explicitly if necessary.

Download

Note that this is using Kotlin 1.1.2-3.

Add the following to the build.gradle:

  1. repositories {
  2. jcenter()
  3. }
  4. dependencies {
  5. compile 'me.eugeniomarletti:android-extras-delegates:1.0.5'
  6. }