自定義輕量級android控件註解工具--金剪刀(自己命名的)(大家都在用)


自定義輕量級android控件註解工具(大家都在用吐舌頭)


金剪刀(

GoldenScissors

)註解工具,是本人寫的一個輕量級的android開發頁面註解工具,代碼量少,非常輕量級.之所以起這


個名字,主要是他jar

包非

常小,源碼也非常少,使用方便,性能高,基本能滿足大部分開發者的需求.字面意思,剪刀嘛也象徵着鋒利,


快速.

   其中此註解工具用到的主要的技術是反射,並且是暴力反射發火.

接下來我主要介紹一下此註解工具怎麼使用以及代碼實現的原理,水平有限,如有不妥或錯誤,請同仁糾正之!


本工具涵蓋三個最主要的註解類型,也是我們開發最常用到的,如下

@LayoutViewCut 綁定activity佈局

@ViewCut 綁定控件資源 省去繁瑣的findViewById

@OnClickCut 控件點擊事件

使用方法:

項目源碼已託管到本人github上,地址: https://github.com/jiangzhengyan/GoldenScissorsViewInject/  請多多關注哦

(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);//點擊

	}

首先要介紹一個自定義的異常(InjectException), 因爲本項目要用到:就是直接繼承異常的一個父類(RuntimeException)

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"));
							}

						}
					});
				}

			}

		}
	}



定義的三個@interface如下

@LayoutViewCut 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutViewCut {

	int  value();
 
}

@ViewCut

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewCut {

	int[] value();

}



@OnClickCut

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public   @interface  OnClickCut {

	int[] value();
}











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章