Android中為按鈕綁定事件的有幾種常見方式,你可以在布局文件中為按鈕設置id,然后在MainActivity中通過findViewById方法獲取按鈕對象實例,再通過setOnClickListener為按鈕綁定事件,如下所示:
//1.獲取控件 btn = (Button)findViewById(R.id.button1); //2.綁定事件 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { callPhone(); } });
你也可以在布局文件中直接為按鈕設置onClick屬性,然后在MainActivity中實現方法(實際應用中相較應用較少,本文主要以前一種方式為契機,故不再贅述基本語法格式)。
當一個應用中有很多按鈕都需要綁定事件,甚至很多按鈕需要綁定的事件具有一定的通用性的時候,我們可以參考一些流行的工具類,利用Java中的反射原理和注解,來寫一個簡單的工具類,幫助我們完成上述工作,讓代碼看起來更簡潔,提高工作效率。
首先還是先簡單介紹一下本文將用到的暴力反射和注解方面的一些知識吧。
反射機制,就是Java中任意一個類,可以通過獲取其字節碼的方式,將其屬性、構造方法、方法和注解等等映射成Method、Constructor、Field、Annotation類,然后對其進行操作。所謂暴力反射是針對類中一些聲明為private的成員,通過obj.setAccessible(true);的方式來強行使用私有成員。
Java中的注解Annotation,平時我們常見的一些jdk提供的注解相信大家一定不會陌生,比如@Override(提示重寫父類方法,如果不能構成重寫的話會報錯);@Deprecated(抑制過時警告);@SuppressWarnings(抑制警告),簡而言之,注解就是給JVM看的注釋。本文將會用到自定義注解,大概寫個小例子說明一下自定義注解的用法:
package com.yuki.vu; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MyInject { int value(); }
@interface就是注解類的標志性聲明了(注意,類成員只能是以下幾種:基本數據類型、Class類型、枚舉類型
元注解: |
@Retention:指定的注解作用范圍 |
值: |
RetentionPolicy.SOURCE java源碼范圍可見 |
RetentionPolicy.CLASS .class字節碼可見 |
RetentionPolicy.RUNTIME 運行的時候都可見 |
@Target:代表定義的注解修飾范圍(屬性,方法,類) |
ElementType.TYPE:注解修飾類 |
ElementType.METHOD:注解修飾方法 |
ElementType.FILED:注解修飾屬性 |
以上只是對反射和注解的簡單介紹,詳細使用還請另尋資料。接下來開始編寫我們的小工具,代碼如下:
MyViewUtils.java文件
package com.yuki.vu; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.app.Activity; import android.view.View; import android.view.View.OnClickListener; public class MyViewUtils { public static void inject(final Activity activity){ //反射屬性 Field[] declaredFields = activity.getClass().getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { Field field = declaredFields[i]; field.setAccessible(true); MyInject annotation = field.getAnnotation(MyInject.class); if (annotation!=null) { int id = annotation.value(); View view = activity.findViewById(id); try { field.set(activity, view); } catch (Exception e) { e.printStackTrace(); } } } //反射方法 Method[] declaredMethods = activity.getClass().getDeclaredMethods(); for (int i = 0; i < declaredMethods.length; i++) { final Method method = declaredMethods[i]; method.setAccessible(true); MyClick annotation = method.getAnnotation(MyClick.class); if (annotation!=null) { int[] value = annotation.value(); for (int j : value) { int id = j; final View btn = activity.findViewById(id); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { method.invoke(activity, btn); } catch (Exception e) { e.printStackTrace(); } } }); } } } } }
MyInject.java文件:
package com.yuki.vu; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MyInject { int value(); }
MyClick.java文件:
package com.yuki.vu; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyClick { int[] value(); }
在掌握了反射和注解用法的基礎上,看懂以上代碼應該不難(代碼有哪里不清楚的地方可以評論留言哈^.^),你可以將這三個文件的源文件直接導入工程,也可以把它們打包成一個jar文件,日后導入libs中使用,具體使用如下:
package com.yuki.vu; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { @MyInject(R.id.tv) private TextView tv; @MyInject(R.id.et) private EditText et; @MyInject(R.id.btn1) private Button btn1; @MyInject(R.id.btn2) private Button btn2; @MyInject(R.id.btn3) private Button btn3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyViewUtils.inject(this); Log.d("tag", ""+btn1.getText()); } @MyClick({R.id.btn1, R.id.btn2, R.id.btn3}) public void submit(View view){ Toast.makeText(this, ((Button)view).getText(), Toast.LENGTH_SHORT).show(); } }
以上就是MainActivity的代碼了。可以看到,在使用工具類的情況下,首先通過@MyInject注解獲取每個帶有id的按鈕控件,再通過MyClick的方法為每個按鈕綁定事件,最后在onCreate方法中通過一句MyViewUtils.inject(this)來完成按鈕與事件的綁定,至此大功告成~撒花
其實以上內容也是從著名的工具類xUtils中參考而來,你可以在github等網站找到這些強大的工具類的源碼以及詳細的使用說明,故本文只為我們自己編寫工具類做一個拋磚引玉的小例子,僅供參考,歡迎交流~