在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