金剪刀(
GoldenScissors
)註解工具,是本人寫的一個輕量級的android開發頁面註解工具,代碼量少,非常輕量級.之所以起這
個名字,主要是他jar
包非
常小,源碼也非常少,使用方便,性能高,基本能滿足大部分開發者的需求.字面意思,剪刀嘛也象徵着鋒利,
快速.
本工具涵蓋三個最主要的註解類型,也是我們開發最常用到的,如下
@LayoutViewCut 綁定activity佈局
@ViewCut 綁定控件資源 省去繁瑣的findViewById
@OnClickCut 控件點擊事件
使用方法:
(1) 把libs下面的GoldenScissors.jar導進自己的項目中或者把library下的源碼防盜自己的項目中
(2) 在onCreate方法中綁定此工具
GoldenScissors.cut(this);
(3) 根據需要,按照以下的方式去使用
1,@LayoutViewCut 註解綁定佈局,(省去setContentView)
在繼承activity的類位置添加註解(如 @LayoutViewCut(R.layout.activity_main)),例如
@LayoutViewCut(R.layout.activity_main)
public class MainActivity extends Activity {
@ViewCut({R.id.tv_1, R.id.tv_2})
private TextView tv1, tv2;
2,@ViewCut,可以代替findviewbyid找控件,在成員變量上面添加
1,@ViewCut(R.id.tv_1).//單個控件
2,@ViewCut({R.id.tv_1}) //單個控件
3,@ViewCut({R.id.tv_1, R.id.tv_2}) //多個控件
如下
@ViewCut({R.id.tv_1, R.id.tv_2})
private TextView tv1, tv2;
@ViewCut(R.id.tv_3)
private TextView tv3;
@ViewCut({R.id.tv_4})
private TextView tv4;
@ViewCut({R.id.tv_5, R.id.tv_6, R.id.tv_7, R.id.tv_8,})
private TextView tv5, tv6, tv7, tv8;
3, @OnClickCut 點擊事件
注:方法的的命名參數名必須爲View,方法名只要符合基本命名規則就行
@OnClickCut({R.id.tv_1, R.id.tv_2, R.id.tv_3, R.id.tv_4, R.id.btn})
private void click(View view) {
switch (view.getId()) {
case R.id.tv_1:
Toast.makeText(this, "點擊了" + "tv1", Toast.LENGTH_SHORT).show();
break;
case R.id.tv_2:
Toast.makeText(this, "點擊了" + "tv2", Toast.LENGTH_SHORT).show();
break;
case R.id.tv_3:
Toast.makeText(this, "點擊了" + "tv3", Toast.LENGTH_SHORT).show();
break;
case R.id.tv_4:
Toast.makeText(this, "點擊了" + "tv4", Toast.LENGTH_SHORT).show();
break;
case R.id.btn:
Toast.makeText(this, "點擊了" + "按鈕 5", Toast.LENGTH_SHORT).show();
break;
}
}
源代碼解析
1, GoldenScissors這個類裏面定義了一個cut方法,裏面包含了三個工具最主要的三個處理註解邏輯的方法.
public static void cut(final Activity activity) {
bindLayout(activity);//佈局
bindFields(activity);//控件
bindMethod(activity);//點擊
}
public class InjectException extends RuntimeException {
private static final long serialVersionUID = -8782914729012957108L;
public InjectException() {
}
public InjectException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
public InjectException(String detailMessage) {
super(detailMessage);
}
public InjectException(Throwable throwable) {
super(throwable);
}
}
下面介紹主要的三個地方法:
/**
* 綁定佈局
*
* @param activity
* 所在對象
*/
private static void bindLayout(Activity activity) {
final Class<? extends Context> clazz = activity.getClass();
LayoutViewCut layoutViewCut = clazz.getAnnotation(LayoutViewCut.class);
if (layoutViewCut != null) {
int layoutResId = layoutViewCut.value();
try {
Method method = clazz.getMethod("setContentView",
new Class[] { Integer.TYPE });
method.invoke(activity, layoutResId);
} catch (Throwable th) {
throw new InjectException(new Throwable(th.getMessage() + " : "
+ th));
}
}
}
/**
* 綁定多個成員變量
*
* @param activity
* 所在對象
*/
private static void bindFields(Activity activity) {
final Class<? extends Context> clazz = activity.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
ArrayList<Integer> filedResIdList = new ArrayList<Integer>();
ArrayList<String> filedNameList = new ArrayList<String>();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
ViewCut injectFiled = field.getAnnotation(ViewCut.class);
if (injectFiled != null) {
String filedName = field.getName();
if (!filedNameList.contains(filedName)) {
filedNameList.add(filedName);
}
int[] resIds = injectFiled.value();
for (int x = 0; x < resIds.length; x++) {
int k = resIds[x];
if (!filedResIdList.contains(k)) {
filedResIdList.add(k);
}
}
}
}
int declaredFieldsLength = filedNameList.size();
int resIdsLength = filedResIdList.size();
if (declaredFieldsLength > resIdsLength) {
throw new InjectException(
new Throwable(
"DeclaredFileds' counts cannot be more than inject ResIds' counts"));
} else if (declaredFieldsLength < resIdsLength) {
throw new InjectException(
new Throwable(
"Inject ResIds' counts cannot be more than DeclaredFileds' counts"));
}
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
ViewCut injectFiled = field.getAnnotation(ViewCut.class);
if (injectFiled != null) {
int resId = filedResIdList.get(i);
View view = activity.findViewById(resId);
field.setAccessible(true);
try {
field.set(activity, view);
} catch (Throwable th) {
throw new InjectException(
new Throwable(
"Inject failed ,maybe your context is null or recorrect"));
}
}
}
}
/**
* 綁定方法,即點擊事件
*
* @param activity
* 所在對象
*/
private static void bindMethod(final Activity activity) {
final Class<? extends Context> clazz = activity.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods) {
OnClickCut injectMetheds = method.getAnnotation(OnClickCut.class);
method.setAccessible(true);
if (injectMetheds != null) {
int[] resIds = injectMetheds.value();
for (int i = 0; i < resIds.length; i++) {
final View view = activity.findViewById(resIds[i]);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
method.invoke(activity, view);
} catch (Throwable th) {
throw new InjectException(
new Throwable(
"Inject method failed,please checked you methed inject names"));
}
}
});
}
}
}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutViewCut {
int value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewCut {
int[] value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClickCut {
int[] value();
}