IoC是什么呢?
我自己也整不明白,我怎么解釋,自己百度去吧
今天干啥,那就弄個注解加載布局加載view 設(shè)置監(jiān)聽吧
廢話不多說,反正我感覺你也不想聽,那就上代碼吧
首先看界面
@ContentView(layoutRes = R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@InjectViews(viewRes = R.id.tv_test)
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InitLayout.inject(this);
textView.setText("來呀打我呀!");
}
@OnClick(viewIds = {R.id.tv_demo})
public void click(View view){
Toast.makeText(getBaseContext(),"click",Toast.LENGTH_LONG).show();
}
@OnLongClick(viewIds = {R.id.tv_test})
public boolean longClic(View view) {
Toast.makeText(getBaseContext(),"longClic",Toast.LENGTH_LONG).show();
return false;
}
}
布局不給了,就是兩個文本,自己寫
然后再給你看看注解
注解activity 布局
/*
TYPE: 用于描述類、接口(包括注解類型) 或enum聲明 Class, interface (including annotation type), or enum declaration
FIELD: 用于描述域 Field declaration (includes enum constants)
METHOD: 用于描述方法 Method declaration
PARAMETER: 用于描述參數(shù) Formal parameter declaration
CONSTRUCTOR: 用于描述構(gòu)造器 Constructor declaration
LOCAL_VARIABLE: 用于描述局部變量 Local variable declaration
ANNOTATION_TYPE: Annotation type declaration
PACKAGE: 用于描述包 Package declaration
TYPE_PARAMETER: 用來標(biāo)注類型參數(shù) Type parameter declaration
TYPE_USE: 能標(biāo)注任何類型名稱 Use of a type
RetentionPolicy
SOURCE:注解只保留在源文件,當(dāng)Java文件編譯成class文件的時候,注解被遺棄;
CLASS:注解被保留到class文件,但jvm加載class文件時候被遺棄,這是默認(rèn)的生命周期;
RUNTIME:注解不僅被保存到class文件中,jvm加載class文件之后,仍然存在;
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int layoutRes();
}
注解初始化view
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectViews {
int viewRes() default 0;
}
注解設(shè)置事件
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ClickBase(listener = "setOnClickListener" ,callback = "onClick",listenerType = View.OnClickListener.class)
public @interface OnClick {
int[] viewIds();
}
再看這個ClickBase
@Target(ElementType.ANNOTATION_TYPE)//在注解之上
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickBase {
//設(shè)置事件得方法名稱
String listener();
//事件回調(diào)的類行
Class<?> listenerType();
//回調(diào)的方法名稱
String callback();
}
好了前期準(zhǔn)備的差不多了,到核心技術(shù)了,不要眨眼
public class InitLayout {
public static void inject(Activity activity) {
injectLayout(activity);
injectViews(activity);
injectEvents(activity);
}
private static void injectViews(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
//獲取到該方法下的變量(全部,不論訪問權(quán)限)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//獲取到注解 InjectViews
InjectViews injectViews = field.getAnnotation(InjectViews.class);
if (injectViews != null) {
//獲取到注解中的布局ID
int viewid = injectViews.viewRes();
// View view = activity.findViewById(viewid) //這個是方式之一,但是不夠檔次
try {
//獲取指定類 (getMethod 第一個是方法名 第二個是參數(shù)的集合 可以用Object[])
Method method = clazz.getMethod("findViewById", int.class);
//執(zhí)行g(shù)etMethod獲取到的方法
Object view = method.invoke(activity, viewid);
//給屬性field賦值
field.set(activity, view);
//設(shè)置訪問權(quán)限
field.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 設(shè)置點擊事件
*
* @param activity
*/
private static void injectEvents(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
//獲取到所有public的方法,包括父類
Method[] methods = clazz.getMethods();
//遍歷方法,拿到有自己注解的方法
for (Method method : methods) {
//一個方法有多個注解
Annotation[] annotations = method.getAnnotations();
/*
遍歷注解,拿到自己定義的注解
其實也可以這樣拿到 某個注解 -》ContentView contentView = clazz.getAnnotation(ContentView.class);
但是這樣會寫死,只支持方法上一種注解
遍歷所有注解,然后拿到每個注解上帶有ClickBase注解的 注解 真是妙哉妙哉妙哉
后面只要寫各種注解上使用ClickBase注解就可以
*/
for (Annotation annotation : annotations) {
//獲取到注解上面的注解
Class<? extends Annotation> annotationType = annotation.annotationType();
if (annotationType != null) {
try {
//拿到方法注解上的注解
ClickBase clickBase = annotationType.getAnnotation(ClickBase.class);
if (clickBase != null) {
//拿到ClickBase的三個重要的值
String callbackStr = clickBase.callback();
String listenerStr = clickBase.listener();
Class<?> listenerType = clickBase.listenerType();
//Aop
ClickListenerHandler handler = new ClickListenerHandler(activity);
//把方法都添加到ClickListenerHandler中
handler.addMethod(callbackStr, method);
//實現(xiàn)代理
Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, handler);
/*
獲取ids的也是可以這樣寫
OnClick onClick = (OnClick) annotation;
int[] ids = onClick.viewIds();
但是這樣又寫死了
*/
// //獲取控件id 的方法
Method valueMethod = annotationType.getDeclaredMethod("viewIds");
// //執(zhí)行獲取id 的方法,拿到id列表
int[] ids = (int[]) valueMethod.invoke(annotation);
//遍歷控件id列表
for (int id : ids) {
View view = activity.findViewById(id);
//獲取到設(shè)置監(jiān)聽的方法
Method clickListener = view.getClass().getMethod(listenerStr, listenerType);
clickListener.invoke(view, listener);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
private static void injectLayout(Activity activity) {
//拿到activity的反射
Class<? extends Activity> clazz = activity.getClass();
//拿到反射類的注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (contentView != null) {
//拿到注解的值
int layout = contentView.layoutRes();
try {
//獲取指定類 (getMethod 第一個是方法名 第二個是參數(shù)的集合 可以用Object[])
Method method = clazz.getMethod("setContentView", int.class);
//執(zhí)行g(shù)etMethod獲取到的方法
method.invoke(activity, layout);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
好了,這個就是核心代碼了
發(fā)現(xiàn)了沒,我們要設(shè)置事件的時候,就要引入一個東西 Aop
用注解的方法,去替掉回調(diào)的方法,nice 看懂了么,不懂沒關(guān)系,我是不會多說的,耗子尾汁
先看看InvocationHandler實現(xiàn)類
public class ClickListenerHandler implements InvocationHandler {
//執(zhí)行方法的對象
private Object target;
//替換掉回調(diào)的方法
private HashMap<String, Method> methodHashMap = new HashMap();
public ClickListenerHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
method = methodHashMap.get(name);
if (method != null) {
return method.invoke(target, args);
}
return null;
}
public void addMethod(String methodName,Method method){
methodHashMap.put(methodName,method);
}
}
行了,代碼上了,然后擴展吧
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ClickBase(listener = "setOnLongClickListener" ,callback = "onLongClick",listenerType = View.OnLongClickListener.class)
public @interface OnLongClick {
int[] viewIds();
}
剩下的自己去鳥補吧