在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