这篇文章来源于 You won’t believe this one weird trick to handle Android Intent extras with Kotlin  ,本来准备翻译一遍,但是担心理解不够深入,索性按着自己的理解整理一遍。十分感谢 @Eugenio Marletti  的思路。
首先,这篇文章可能会涉及到的知识点有:
伴生对象 对象表达式与对象声明 扩展函数 扩展属性 高阶函数( lambda 表达式) 带接收者的函数字面值 委托属性 Java 的实现方式 在 Android 开发中, Activity 之间的数据传递是不可避免的。初次接触 Android 编程的时候,许多教程会写出这样的代码:
1 2 3 4 5 6 7 Intent  intent  =  new  Intent (context, AimActivity.class);intent.putExtra("msg" , message); startActivity(intent); this .message = getIntent().getStringExtra("msg" );
这样写当然没有错,的确达到了传递数据的目的,但是,这却会让代码难以维护。稍微有些开发经验的,都会选择将 Extra 信息的键值抽出变为常量,并且把许多类似的键值放在同一个地方,避免出现键值的冲突。
为了更好的可读性,还有一些人会这样去封装 Intent :
1 2 3 4 5 6 7 8 9 private  static  final  String  MSG_KEY  =  "key for message" ;@Nullable  public  static  String getMessage (@NonNull  Intent intent)  {  return  intent.getStringExtra(MSG_KEY); } public  static  void  setMessage (@NonNull  Intent intent, String message)  {  intent.putExtra(MSG_KEY, message); } 
这样一来,读写 Intent 的确如读写类成员属性一般了,可是,不得不说,这也极大地增加了代码的编写量。当然,或者可以通过注解、动态生成代码的方式来解决这一问题,但这不是本篇文章的解决方案。
Kotlin 的登场 在 Java 的实现方式中,最适合阅读、最符合面向对象思想的数据传递方式当属最后一种,那,下面就用一些 Kotlin 的特性来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object  IntentOptions {  private  const  val  MSG_KEY = "key for message"    fun  Intent.getMessage ()    fun  Intent.setMessage (message: String ?)      putExtra(MSG_KEY, message)   } } with(IntentOptions) {   intent.setMessage("message" )   message = intent.getMessage() } 
可以看到,利用 Kotlin 提供的扩展函数的特性,我们就可以在 Intent 对象上直接使用 getter/setter 了,这是 Java 语言做不到的。
需要注意的是 with 表达式的使用,这涉及到 扩展函数  的作用域问题。在 Kotlin 中,扩展函数的作用范围只在其定义范围内。一般而言,我们把许多扩展函数定义在了顶级作用域中,这样在整个 App ,被扩展的对象实例都可以使用该函数。但是考虑到,我们不能在 Intent 对象上无限制地添加 getter/setter ,所以利用 object ,让这些扩展函数只在该对象的作用域内有效。在实际使用中,这个 object 可以是某个 Activity 的伴生对象。
到这里,我们可以更进一步,使用 扩展属性  ,让赋值 / 取值的过程更符合 Kotlin 的语言规范:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object  IntentOptions {  private  const  val  MSG_KEY = "key for message"    var  Intent.message: String?   	get () = getStringExtra(MSG_KEY)   	set (message) {       putExtra(MSG_KEY, message)   	} } with(IntentOptions) {   intent.message = "message"    message = intent.message } 
嗯,不论写那个 object 的过程怎样,至少,在使用这样的 Intent 方面,体验到了读写原生对象的便利啊。
Kotlin 中的委托 委托?为什么要用委托?上面的代码我们使用委托的模式改写一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  IntentExtraStringDelegate (val  key: String) {  fun  getValue (intent: Intent )    	intent.getStringExtra(name)   fun  setValue (intent: Intent , value: String ?)      intent.putExtra(name, value)   } } object  IntentOptions {  private  val  messageDelegate = IntentExtraStringDelegate("key for message" )   var  Intent.message: String?   	get () = messageDelegate.getValue(this )   	set (message) = messageDelegate.setValue(this , message) } 
可以看到,委托就是把 Intent 内容的读写操作抽取出来,以便复用。进行了这样的抽取之后,我们又可以在 Kotlin 的语言特性中找到这样的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 class  IntentExtraString (private  val  key: String) {  operator  fun  getValue (intent: Intent , property: KProperty <*>)    	intent.getStringExtra(key)   operator  fun  setValue (intent: Intent , property: KProperty <*>, value: String ?)      intent.putExtra(key, value)   } } object  IntentOptions {  var  Intent.message by  IntentExtraString("key for message" ) } 
啊哈,这样一来,相当于仅仅是对 Intent 内的变量进行了一下声明,就可以在对应的范围内使用了!而存储的键值,也完全可以省略,直接使用字段名:
1 2 3 4 5 6 7 8 9 10 11 class  IntentExtraString (private  val  key: String? = null ) {  private  val  KProperty<*>.extraName: String   	get () = this @IntentExtraString .key ?: name   operator  fun  getValue (intent: Intent , property: KProperty <*>)    	intent.getStringExtra(property.extraName)   operator  fun  setValue (intent: Intent , property: KProperty <*>, value: String ?)      intent.putExtra(property.extraName, value)   } } 
一般而言,在 Activity 可以这样使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Activity  : AppCompatActivity () {  companion  object  IntentOptions {     var  Intent.id by  IntentExtraString()     var  Intent.name by  IntentExtraString()     var  Intent.message by  IntentExtraString()   }   fun  test (intent: Intent )      intent.id = "1"      intent.name = "pass"      intent.message = "message"    } } fun  testOutSide (intent: Intent )   val  id = intent.id   val  name = intent.name   val  message = intent.message } 
以上,就是使用 Kotlin 优化 Intent 数据传输的基本思路。当然,在这个思路下,还有许多可以封装的,比如,自定义类型数据的传输 —— 可以去看一看原作者的开源库 android-extras-delegates