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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值