android使用篇 註解實現綁定控件實例化

在android使用篇(三) MVC模式中提到一個問題:

1) 視圖層(View):一般採用XML文件進行界面的描述,使用的時候可以非常方便的引入,但是用xml編寫了,又需要在Acitvity聲明並且實例化,有點麻煩,考慮能否做一個類似註解實現匹配,或者寫一個類獲取xml的各個節點然後自動進行封裝,當然,這只是個想法,以後再實現。

今天終於把這個想法實現了,使用IOC註解實現對activity中控件的實例化。

先普及一下java的反射機制和註解機制的知識:

以下引用大神的兩篇文章:

JAVA反射機制

java 註解

完成後只需要: @ViewInject(id=R.id.btn1,click="btnClick") TextView btn1; 即可完成實例化,並添加點擊事件

基本思路:

一,public abstract class D3Activity extends Activity 寫一個類繼承Activity。

二,重寫 setContentView 在此方法實現註解。

三,Field[] fields = activity.getClass().getDeclaredFields(); 獲取activity中的字段屬性

四, field.getAnnotation(ViewInject.class); 獲取字段的註解屬性

五, field.set(activity,sourceView.findViewById(viewId)); 實例化控件

大功告成,到此已實現了註解實現對android中activity和xml文件的實例化問題。

另外也可以實現註解對控件的事件添加,詳細


分三個類實現:

實現註解類:

註解類可注入 id---對應xml的id,各種點擊事件,可自己定義

?
1
2
3
4
5
6
7
8
9
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    public int id() default 0;
    public String click() default "";
    public String longClick() default "";
    public String itemClick() default "";
    public String itemLongClick() default "";
}


重寫activity類,使用反射和註解實現實例化並加入事件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public abstract class D3Activity extends Activity {
 
 
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
        initInjectedView(this);
    }
 
 
    public void setContentView(View view, LayoutParams params) {
        super.setContentView(view, params);
        initInjectedView(this);
    }
 
 
    public void setContentView(View view) {
        super.setContentView(view);
        initInjectedView(this);
    }
     
 
    private void initInjectedView(Activity activity){
        initInjectedView(activity, activity.getWindow().getDecorView());
    }
     
     
    private void initInjectedView(Object activity,View sourceView){
        Field[] fields = activity.getClass().getDeclaredFields();   //獲取字段
        if(fields!=null && fields.length>0){
            for(Field field : fields){
                try {
                    field.setAccessible(true);   //設爲可訪問
                     
                    if(field.get(activity)!= null )
                        continue;
                 
                    ViewInject viewInject = field.getAnnotation(ViewInject.class);
                    if(viewInject!=null){
                         
                        int viewId = viewInject.id();
                        if(viewId == 0)
                            viewId = getResources().getIdentifier(field.getName(), "id",getPackageName());
                        if(viewId == 0)
                            Log.e("D3Activity", "field "+ field.getName() + "not found");
                         
                        //關鍵,註解初始化,相當於 backBtn = (TextView) findViewById(R.id.back_btn);
                        field.set(activity,sourceView.findViewById(viewId)); 
                        //事件
                        setListener(activity,field,viewInject.click(),Method.Click);
                        setListener(activity,field,viewInject.longClick(),Method.LongClick);
                        setListener(activity,field,viewInject.itemClick(),Method.ItemClick);
                        setListener(activity,field,viewInject.itemLongClick(),Method.itemLongClick);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
     
    private void setListener(Object activity,Field field,String methodName,Method method)throws Exception{
        if(methodName == null || methodName.trim().length() == 0)
            return;
         
        Object obj = field.get(activity);
         
        switch (method) {
            case Click:
                if(obj instanceof View){
                    ((View)obj).setOnClickListener(new EventListener(activity).click(methodName));
                }
                break;
            case ItemClick:
                if(obj instanceof AbsListView){
                    ((AbsListView)obj).setOnItemClickListener(new EventListener(activity).itemClick(methodName));
                }
                break;
            case LongClick:
                if(obj instanceof View){
                    ((View)obj).setOnLongClickListener(new EventListener(activity).longClick(methodName));
                }
                break;
            case itemLongClick:
                if(obj instanceof AbsListView){
                    ((AbsListView)obj).setOnItemLongClickListener(new EventListener(activity).itemLongClick(methodName));
                }
                break;
            default:
                break;
        }
    }
     
    public enum Method{
        Click,LongClick,ItemClick,itemLongClick
    }

事件類: 實現了 OnClickListener, OnLongClickListener, OnItemClickListener,OnItemLongClickListener ,可以自己擴展

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public class EventListener implements OnClickListener, OnLongClickListener, OnItemClickListener,OnItemLongClickListener {
 
    private Object handler;
     
    private String clickMethod;
    private String longClickMethod;
    private String itemClickMethod;
    private String itemLongClickMehtod;
     
    public EventListener(Object handler) {
        this.handler = handler;
    }
     
    public EventListener click(String method){
        this.clickMethod = method;
        return this;
    }
     
    public EventListener longClick(String method){
        this.longClickMethod = method;
        return this;
    }
     
    public EventListener itemLongClick(String method){
        this.itemLongClickMehtod = method;
        return this;
    }
     
    public EventListener itemClick(String method){
        this.itemClickMethod = method;
        return this;
    }
     
    public boolean onLongClick(View v) {
        return invokeLongClickMethod(handler,longClickMethod,v);
    }
     
    public boolean onItemLongClick(AdapterView<!--?--> arg0, View arg1, int arg2,long arg3) {
        return invokeItemLongClickMethod(handler,itemLongClickMehtod,arg0,arg1,arg2,arg3);
    }
     
    public void onItemClick(AdapterView<!--?--> arg0, View arg1, int arg2, long arg3) {
         
        invokeItemClickMethod(handler,itemClickMethod,arg0,arg1,arg2,arg3);
    }
     
    public void onClick(View v) {
         
        invokeClickMethod(handler, clickMethod, v);
    }
     
     
    private static Object invokeClickMethod(Object handler, String methodName,  Object... params){
        if(handler == null) return null;
        Method method = null;
        try{  
            method = handler.getClass().getDeclaredMethod(methodName,View.class);
            if(method!=null)
                return method.invoke(handler, params); 
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }
         
        return null;
         
    }
     
     
    private static boolean invokeLongClickMethod(Object handler, String methodName,  Object... params){
        if(handler == null) return false;
        Method method = null;
        try{  
            //public boolean onLongClick(View v)
            method = handler.getClass().getDeclaredMethod(methodName,View.class);
            if(method!=null){
                Object obj = method.invoke(handler, params);
                return obj==null?false:Boolean.valueOf(obj.toString());
            }
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }
         
        return false;
         
    }
     
     
     
    private static Object invokeItemClickMethod(Object handler, String methodName,  Object... params){
        if(handler == null) return null;
        Method method = null;
        try{  
            ///onItemClick(AdapterView<!--?--> arg0, View arg1, int arg2, long arg3)
            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class);
            if(method!=null)
                return method.invoke(handler, params); 
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }
         
        return null;
    }
     
     
    private static boolean invokeItemLongClickMethod(Object handler, String methodName,  Object... params){
        if(handler == null) throw new RuntimeException("invokeItemLongClickMethod: handler is null :");
        Method method = null;
        try{  
            ///onItemLongClick(AdapterView<!--?--> arg0, View arg1, int arg2,long arg3)
            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class);
            if(method!=null){
                Object obj = method.invoke(handler, params);
                return Boolean.valueOf(obj==null?false:Boolean.valueOf(obj.toString()));   
            }
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }
         
        return false;
    }
}


到此已經完成了,只需要這樣即可實例化:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MainActivity extends D3Activity {
     
    //@ViewInject EditText input;   //id和屬性名相同,自動匹配
    @ViewInject(id = R.id.input) EditText editText;    
    @ViewInject(click="btnClick") TextView btn1,btn2,btn3;
     
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
    
 
    public void btnClick(View v){
         
        switch (v.getId()) {
        case R.id.btn1:
            btn1.setText(editText.getText().toString());
            Toast.makeText(getApplicationContext(), "111", Toast.LENGTH_SHORT).show();
            break;
         
        case R.id.btn2:
            Toast.makeText(getApplicationContext(), "222", Toast.LENGTH_SHORT).show();
 
            break;
             
        case R.id.btn3:
            Toast.makeText(getApplicationContext(), "333", Toast.LENGTH_SHORT).show();
            break;
 
        default:
            break;
        }
         
    }
     
}

對應xml佈局文件:

?
1
2
3
4
5
6
7
8
9
10
11
<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical">
 
     
    <edittext android:id="@+id/input" android:layout_width="fill_parent" android:layout_height="wrap_content">
    <textview android:id="@+id/btn1" android:layout_margintop="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="設置自己">
    <textview android:id="@+id/btn2" android:layout_margintop="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="btn2">
     
     
    <textview android:id="@+id/btn3" android:layout_margintop="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="btn3">
</textview></textview></textview></edittext></linearlayout>


源碼已經放在了github,有興趣的可以去看看 :https://github.com/mozhenhau/injectAndroid.git

發佈了49 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章