在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
类委托
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val b = Bean("hello world")
Delegation(b).delegate()
}
}
interface IDelegateListener {
fun delegate()
}
class Bean(val s: String) : IDelegateListener {
override fun delegate() {
println("bean ----> $s")
}
}
class Delegation(delegateListener: IDelegateListener) : IDelegateListener by delegateListener
由输出结果可以看到:Delegation
类并没有实现 IDelegateListener
中的 delegate()
方法,而是通过by
这个关键字,将本应该实现的方法委托给了Bean
,由Bean
来实现方法
委托属性
定义一个委托属性的语法是:
val/var
,: by by
后面的就是属性的委托。委托属性不需要实现接口,只需要用operator
修饰的setValue()
getValue
函数。如果是val属性 则不用提供setValue()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bean = Bean()
println("bean ---> ${bean.string}")
bean.string="2"
println("bean ---> ${bean.string}")
}
}
class Bean {
var string: String by Delegator()
}
class Delegator {
var temp = "1"
operator fun getValue(ref: Any?, p: KProperty<*>): String {
return "Delegator --> ${p.name} --> $temp"
}
operator fun setValue(ref: Any?, p: KProperty<*>, value: String) {
temp = value
}
}
参数说明:
-
ref
属性拥有者 -
p
属性的描述 -
value
属性的值
标准委托
延迟属性 lazy
通过lazy
可以定义一个懒加载属性,只有val
类型的属性才能延迟初始化,且只初始化一次,lazy()
是接受一个 lambda 并返回一个 Lazy
实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get()
会执行已传递给 lazy()
的 lambda 表达式并记录结果, 后续调用 get()
只是返回记录的结果。
class MainActivity : AppCompatActivity() {
val lazyValue:String by lazy {
println("1 ---->赋值")
"lazy"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
println("2 ---->$lazyValue")
println("3 ---->$lazyValue")
}
}
可以从运行结果看出:只有在第一次使用的时候才将
"lazy"
赋值
默认情况下,对于 lazy
属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION
作为参数传递给 lazy()
函数。 而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE
模式, 它不会有任何线程安全的保证和相关的开销。
可观察属性 Observable
Delegates.observable()
接受两个参数:初始值和修改时处理程序(handler)。 每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值和新值
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val observableUse = ObservableUse()
observableUse.s = "1"
observableUse.i = "2"
println("observable ----> ${observableUse.s}")
println("observable ----> ${observableUse.i}")
}
}
class ObservableUse {
var s: String by Delegates.observable("0") { property, oldValue, newValue ->
println("observable ----> $property,$oldValue,$newValue")
}
var i: String by Delegates.vetoable("3") { property, oldValue, newValue ->
newValue.length > oldValue.length
}
}
通过可观察属性,就可以实现一些观察者模式的方法,如果你想能够截获一个赋值并“否决”它,就使用
vetoable()
取代
observable()
。 在属性被赋新值生效
之前会调用传递给
vetoable
的处理程序。
实际应用场景
通过委托,我们可以封装一些工具类,例如 Intent 取值 SharedPrefrences 取值等:
/**
* kotlin 委托传值工具
*/
class ExtraDelegator(private val extraKey:String , private val defaultValue:T) {
private var extra: T? = null
operator fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
extra = getExtra(extra, extraKey, thisRef)
return extra ?: defaultValue
}
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
extra = getExtra(extra, extraKey, thisRef)
return extra ?: defaultValue
}
fun extraDelegate(extra: String, default: T) = ExtrasDelegate(extra, default)
fun extraDelegate(extra: String) = extraDelegate(extra, null)
@Suppress("UNCHECKED_CAST")
private fun getExtra(oldExtra: T?, extraKey: String, thisRef: AppCompatActivity): T? =
oldExtra ?: thisRef.intent?.extras?.get(extraKey) as T?
@Suppress("UNCHECKED_CAST")
private fun getExtra(oldExtra: T?, extraKey: String, thisRef: Fragment): T? =
oldExtra ?: thisRef.arguments?.get(extraKey) as T?
}
使用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 传值
content_tv.setOnClickListener {
val intent = Intent(this@MainActivity, TestActivity::class.java)
intent.putExtra("string","value")
startActivity(intent)
}
}
}
class TestActivity:AppCompatActivity(){
val string:String? by extraDelegate("string") // 通过委托接收
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
println("TestActivity ------> $string")
}
}
结语
通过委托和扩展函数可以封装很多有趣的工具类,从Java
过度到Kotlin
的感觉就好像从 Eclipse
过渡到 Android Studio
一开始觉得麻烦,但是用一用就觉得:诶,还可以,到现在已经基本不想再用Java
写了 , 对于新的东西,还是要去敢于尝试。