Android進階: 註解從入門到精通
註解實現三部曲
使用場景
- EventBus使用
@Subscriber(mode = ThreadMode.MAIN, tag = EventTag.STORE_OUT_SUMMARIZING) internal fun refresh(list: Any) { getOutList() }
- bufferknife點選事件使用
@OnClick(R.id.btn_login) public void onViewClicked() { }
原理:和監聽有點類似,通過定義一個介面實現註解標籤的使用,然後定義一個類,通過反射對所有使用註解的檔案進行二級操作。
那麼問題來了,如果我們想使用註解,該如何做暱?
使用三部曲
- 1.定義一個介面
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Action { public String source() default "nothing"; }
解釋:
@Target
@Target說明了Annotation所修飾的物件範圍:Annotation可被用於 packages、types(類、介面、列舉、Annotation型別)、型別成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數)。在Annotation型別的宣告中使用了target可更加明晰其修飾的目標。 取值(ElementType)有: 1.CONSTRUCTOR:用於描述構造器 2.FIELD:用於描述域 3.LOCAL_VARIABLE:用於描述區域性變數 4.METHOD:用於描述方法 5.PACKAGE:用於描述包 6.PARAMETER:用於描述引數 7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告
@Retention
@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在原始碼中,而被編譯器丟棄;而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機器忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命週期”限制。 取值(RetentionPoicy)有: 1.SOURCE:在原始檔中有效(即原始檔保留) 2.CLASS:在class檔案中有效(即class保留) 3.RUNTIME:在執行時有效(即執行時保留)
- 2.註解事件處理器
package com.chen.annotation import android.view.View import java.lang.reflect.InvocationHandler import java.lang.reflect.Method import java.lang.reflect.Proxy import king.bird.annotation.Action /** * <pre> * author : Wp * e-mail : [email protected] * time: 2018/09/10 * desc: 註解例項 * version: 1.0 *</pre> */ class ActionInstaller { companion object { fun processAnnotations(client: Any) { val clientClass = client.javaClass for (m in clientClass.declaredMethods) { //獲取指定Annotation物件 val listener = m.getAnnotation(Action::class.java!!) if (listener != null) { try { val f = clientClass.getDeclaredField(listener.source) f.isAccessible = true //控制元件物件 val focusView = f.get(client) addListener(focusView, client, m) } catch (e: Exception) { e.printStackTrace() } } } } @Throws(Exception::class) private fun addListener(focusView: Any, client: Any, m: Method) { val handler = InvocationHandler { proxy, method, args -> //場景類呼叫 onBtnClick() 方法 m.invoke(client) } val onClickListener = Proxy.newProxyInstance(null, arrayOf<Class<*>>(View.OnClickListener::class.java), handler) val setOnClickListenerMethod = focusView.javaClass.getMethod("setOnClickListener", View.OnClickListener::class.java) setOnClickListenerMethod.invoke(focusView, onClickListener) } } }
- 3.實際應用
@Action(source = "mBtnTest") fun onBtnClick() { Log.e("Test", "mBtnTest點選") }
專案demo詳見Github
參與貢獻
- Fork 本專案
- 新建 Feat_xxx 分支
- 提交程式碼
- 新建 Pull Request
github地址
-
博主推薦:ofollow,noindex">https://github.com/pengMaster/marry