Android自定義工具類獲取按鈕並綁定事件(利用暴力反射和註解)

Android中爲按鈕綁定事件的有幾種常見方式,你能夠在佈局文件中爲按鈕設置id,而後在MainActivity中經過findViewById方法獲取按鈕對象實例,再經過setOnClickListener爲按鈕綁定事件,以下所示:java

//1.獲取控件
btn = (Button)findViewById(R.id.button1);
//2.綁定事件
btn.setOnClickListener(new OnClickListener() {
            
    @Override
    public void onClick(View v) {
        callPhone();                
    }
            
});

 

你也能夠在佈局文件中直接爲按鈕設置onClick屬性,而後在MainActivity中實現方法(實際應用中相較應用較少,本文主要之前一種方式爲契機,故再也不贅述基本語法格式)。android

 

當一個應用中有不少按鈕都須要綁定事件,甚至不少按鈕須要綁定的事件具備必定的通用性的時候,咱們能夠參考一些流行的工具類,利用Java中的反射原理和註解,來寫一個簡單的工具類,幫助咱們完成上述工做,讓代碼看起來更簡潔,提升工做效率。git

首先仍是先簡單介紹一下本文將用到的暴力反射和註解方面的一些知識吧。github

反射機制,就是Java中任意一個類,能夠經過獲取其字節碼的方式,將其屬性、構造方法、方法和註解等等映射成Method、Constructor、Field、Annotation類,而後對其進行操做。所謂暴力反射是針對類中一些聲明爲private的成員,經過obj.setAccessible(true);的方式來強行使用私有成員。app

Java中的註解Annotation,平時咱們常見的一些jdk提供的註解相信你們必定不會陌生,好比@Override(提示重寫父類方法,若是不能構成重寫的話會報錯);@Deprecated(抑制過期警告);@SuppressWarnings(抑制警告),簡而言之,註解就是給JVM看的註釋。本文將會用到自定義註解,大概寫個小例子說明一下自定義註解的用法:ide

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文件:this

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等網站找到這些強大的工具類的源碼以及詳細的使用說明,故本文只爲咱們本身編寫工具類作一個拋磚引玉的小例子,僅供參考,歡迎交流~

相關文章
相關標籤/搜索