常用的by lazy 延遲委托 , by Delegates.observable() 可觀察屬性委托, by Delegates.nonNull()等等
語法是: val/var<屬性名>:<類型> by<表達式>贫途。在 by后面的表達式是該委托
屬性對應的get() (和set())會被委托給它的getValue()和setValue()方法藕施。
所以,kotlin中的代理僅僅是代理了get 和 set 兩個方法
屬性的委托不必實現(xiàn)任何的接口,但是需要重載操作符getValue()函數(shù)(和setValue()——對于var屬性)
但是對于val可以實現(xiàn)ReadOnlyProperty,var實現(xiàn)ReadWriteProperty接口(就是幫你實現(xiàn)兩個需要重載的操作符的接口)來更快的進行自定義委托.
//此段代碼為ReadWriteProperty的接口
public interface ReadWriteProperty<in R, T> {
public operator fun getValue(thisRef: R, property: KProperty<*>): T
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
那么他們究竟是怎么工作的呢?
我們來看看nonNull()委托的代碼吧
我初始化了一個Int對象,且用委托表示int1不可以為空
var int1 : Int by Delegates.notNull()
那么我們進入notNull()的代碼里查看他的實現(xiàn)
public fun <T: Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
很明顯,代理給一個ReadWriteProperty類了
那么NotNullVar()是什么呢
private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
我來解釋一下,當給int1復制的時候,就會自動調用上面的setValue(),其中的三個參數(shù)
第一個thisRef表示持有該對象的對象,即該int1的所有者.
第二個參數(shù) property 是該值的類型,
第三個參數(shù) value 就是屬性的值了
在第一次調用setvalue的時候,將該值存到value中,getvalue的時候對value進行是否為空的判斷.空就拋異常,這就完成了nonNull的委托
類似的我們看看by Delegates.observable() 這個委托
先看看該委托的使用方法吧
var int2 : Int by Delegates.observable(1){
property, oldValue, newValue ->
//oldvalue是修改前的值,newValue是修改后的值
}
該委托的實現(xiàn)
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
最終委托到的對象,注意這是一個抽象類
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value //修改前的值
//beforeChange一直返回true 不知此段代碼意義何在
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value //修改后的值
//調用上一段代碼中重寫的方法
afterChange(property, oldValue, value)
}
}
很明顯,在setValue的過程中,調用了afterChange(),而afterChange是你使用該代理的時候傳入的lambda,所以每次修改該對象的值的時候,都會調用你傳入的函數(shù),實現(xiàn)了對對象的值改變的觀察.
看完上面兩個例子,我們來自定義一個委托用來實現(xiàn)finViewById吧
當然例子很簡陋,只能在activity中使用,僅供參考
class MainActivity : AppCompatActivity() ,MainContract.View {
val imageView : ImageView by bindView(R.id.imageView)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
imageView.setImageDrawable(null)
}
}
fun <T: View> bindView( id : Int): FindView<T> = FindView(id)
class FindView<T : View >(val id:Int) : ReadOnlyProperty<Any?,T>{
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
if(this.value == null) {
this.value = (thisRef as Activity).findViewById<T>(id)
}
return this.value?:throw RuntimeException("can not find this view")
}
var value : T? = null
}
但是,為什么thisref 可以強轉成activity呢?上面已經說了thisRef是該對象的持有者,在上面的代碼中,即MainActivity.
我們將kotlin代碼轉成字節(jié)碼再轉到java代碼中查看
//反射得到該類的屬性
static final KProperty[] $$delegatedProperties =
new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(
Reflection.getOrCreateKotlinClass(MainActivity.class),
"imageView", "getImageView()Landroid/widget/ImageView;"))};
//真正的代理類
@NotNull
private final FindView imageView$delegate = MainActivityKt.bindView(2131230801);
//通過代理類得到imageview
@NotNull
public final ImageView getImageView() {
//在這里,我們就一清二楚的知道了getValue傳入的兩個參數(shù)究竟是什么了!!
return (ImageView)this.imageView$delegate.getValue(this, $$delegatedProperties[0]);
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(2131361819);
//通過代理類得到imageview
this.getImageView().setImageDrawable((Drawable)null);
}
代理類的實現(xiàn)
public final class FindView implements ReadOnlyProperty {
@Nullable
private View value;
private final int id;
@NotNull
public View getValue(@Nullable Object thisRef, @NotNull KProperty property) {
Intrinsics.checkParameterIsNotNull(property, "property");
if(this.value == null) {
if(thisRef == null) {
throw new TypeCastException("null cannot be cast to non-null type android.app.Activity");
}
this.value = ((Activity)thisRef).findViewById(this.id);
}
View var10000 = this.value;
if(this.value != null) {
return var10000;
} else {
throw (Throwable)(new RuntimeException("can not find this view"));
}
}
// $FF: synthetic method
// $FF: bridge method
public Object getValue(Object var1, KProperty var2) {
return this.getValue(var1, var2);
}
@Nullable
public final View getValue() {
return this.value;
}
public final void setValue(@Nullable View var1) {
this.value = var1;
}
public final int getId() {
return this.id;
}
public FindView(int id) {
this.id = id;
}
}