传统方式
1.Activity内部封装跳转逻辑
class VideoDetailActivity : BaseActivity(), InitUI, View.OnClickListener {
companion object {
fun start(
activity: Activity,
data: ArrayList<VideoBean>,
position: Int
) {
val intent = Intent(activity, VideoDetailActivity::class.java).apply {
this.putParcelableArrayListExtra("data",data)
this.putExtra("position",position)
}
activity.startActivity(intent)
}
}
- 获取值
override fun onCreate(savedInstanceState: Bundle?) {
val position = intent.getIntExtra("position",0)
val data = intent.getParcelableArrayListExtra<VideoBean>("data")
}
3.优缺点
优点:
- 大家都很熟悉,几乎没有阅读成本以及学习成本;
- 值类型显而易见,intent.getIntExtra("position",0),明确知道获取值的类型是int;
缺点:
- key跟接收值的变量名定义似乎重复了,val position = intent.getIntExtra("position",0),key是"position",变量名名也是position;
- 对应获取值,需要明确知道使用哪个api(getIntExtra、getStringExtra等),有点不太智能(程序员都是很懒的);
- getXXXExtra看起来像是模板代码,一旦传递的参数较多,代码就显得很冗余;
思考
- 设置参数,有没有办法像给HashMap put参数一样那么简单呢?
- 是否可以把接收参数的变量名当成key来使用呢?
- 是否可以不使用getXXXExtra方式来获取参数呢?
针对以上的思考,有如下设计:
扩展函数+属性委托传参
- 扩展函数,key value方式设置参数
给Intent增加扩展函数set,operator是重载运算符,以下代码定义: 给Intent增加set扩展函数set,且重载它的运算符,那么就可以像HashMap那样设置参数,解决了思考1。
//定义
operator fun Intent.set(key: String, value: Any) {
when (value) {
is Int -> {
this.putExtra(key, value)
}
is ArrayList<*> -> {
this.putParcelableArrayListExtra(key, value as ArrayList<Parcelable>)
}
}
}
//调用
val intent = Intent(activity, VideoDetailActivity::class.java).apply {
this["data"] = data
this["position"] = position
}
这里就可以只关注设置参数,不用关心应该调用哪个具体的函数。简单点说,就是可以更关注业务。
- Kotlin委托方式获取值
//定义属性委托类,只读符合业务场景
class IntentsProperty<in A : Any, out T : Any>(private val f:(()->Bundle?)) :
ReadOnlyProperty<A, T> { //1
private var value: T? = null //2
override operator fun getValue(thisRef: A, property: KProperty<*>): T {//3
value?.let { return it }//4
val name = property.name///5
return ((f.invoke()?.get(name)) as T).let {
value = it//6
it
}
}
}
//定义Activity的扩展函数
inline fun <reified T : Any> Activity.intents(): IntentsProperty<Any, T> {//7
return IntentsProperty{
this.intent.extras//8
}
}
//调用
private val position: Int by intents()// 9
private val data: ArrayList<VideoBean> by intents()
注释1:
- 定义属性委托类IntentsProperty实现ReadOnlyProperty接口;
- 第一个泛型in A : Any,表示被委托属性所在的类,因为要在Activity以及Fragment都可以使用,所以传入Any;- 第二个泛型out T : Any,表示getValue函数返回的类型,因为被委托的属性可能是任意类型,所以同样传入Any;
- private val f:(()->Bundle?),需传入可以获取Bundle对象的高阶函数;
注释2:value用来保存值,避免重复从Bundle中获取;
注释3:当被委托属性被调用,getValue函数会被触发;第一参数为被委托属性所在类的对象,第二个参数为被委托属性的信息封装类;
注释4:当有值,即可返回;
注释5:获取被委托属性的名称,名称即为key,这里解决了思考2;
注释6:调用高阶函数获取Bundle,从其获取传递过来的值,并保存起来;
注释7:定义Activity的扩展函数intents,那么就可以在Activity使用by intents()处理属性委托,这里解决了思考3;
注释8:传入高阶函数this.intent.extras;
3.优缺点
优点:
- 参数名就是获取参数的key,保证传参key跟取参key一致,相当于一种协议;
- 设置参数以及获取值,可以不用关心具体调用哪个函数;
缺点:
- 只能用在Kotlin;
- 有一定的学习成本;