文章目录
1 简介
此框架类似XUtils里面的Inject工具。
实现的功能是
Activity中初始化布局
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
控件初始化
@ViewInject(R.id.btn_inject_view)
Button btnInjectView;
监听事件
@onClick(R.id.btn_event_onclick)
public void click(View view){
}
2 布局初始化
2.1 创建注解ContentView
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {
int value();
}
2.2 注入工具类
public class InjectUtils {
public static void inject(Context context){
injectLayout(context);
}
/**
* 注入布局
* @param context
*/
public static void injectLayout(Context context){
int layoutId = 0;
Class<?> clazz = context.getClass();
//1 拿到MainActivity类上面的注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
if(contentView!=null){
//2 获取注解的值
layoutId = contentView.value();
try {
//3 获取setContentView()方法
Method method = clazz.getMethod("setContentView",int.class);
//4 调用setContentView()方法
method.invoke(context,layoutId);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
2.3 在Activity中调用工具类
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectUtils.inject(this);
}
2.4 4 使用注解
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
此时布局已经能加载界面上。
3 控件初始化
3.1 注解ViewInject
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ViewInject {
int value();
}
3.2 注入工具类中添加控件注解方法
public static void inject(Context context){
injectView(context);
}
/**
* 注入控件
* @param context
*/
public static void injectView(Context context){
Class<?> clazz = context.getClass();
//1 获取到MainActivity里面所有的成员变量 包含textView
Field[] fields= clazz.getDeclaredFields();
for(Field field:fields){
//2 得到成员你变量的注解
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if(viewInject!=null){
//3 拿到id R.id.text
int valueId = viewInject.value();
try {
Method method = clazz.getMethod("findViewById",int.class);
//4 反射调用方法 控件被初始化
View view = (View)method.invoke(context,valueId);
field.setAccessible(true);
field.set(context,view);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
3.3 使用注解
@ViewInject(R.id.btn_inject_view)
Button btnInjectView;
4 注入事件
4.1 注解ViewInject
此注解用来修饰事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface EventBase {
/**
* 设置监听的方法
* @return
*/
String listenerSetter();
/**
* 事件类型
* @return
*/
Class<?> listenerType();
/**
* 回调方法
* 事件被触发后,执行回调方法名称
* @return
*/
String callBackMethod();
}
点击事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter = "setOnClickListener",
listenerType = View.OnClickListener.class,
callBackMethod = "onClick")
public @interface onClick {
int[] value();
}
ListView中的条目点击事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter="setOnItemClickListener",
listenerType = AdapterView.OnItemClickListener.class,
callBackMethod = "onItemClick")
public @interface OnItemClick {
int[] value();
}
长按事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter = "setOnLongClickListener",
listenerType = View.OnLongClickListener.class,
callBackMethod = "onLongClick")
public @interface OnLongClick {
int[] value() default -1;
}
4.2 注入事件
/**
* 注入事件
*/
private static void injectEvents(Context context){
Class<?> clazz = context.getClass();
//获取Activity里面的所有方法
Method[] methods = clazz.getDeclaredMethods();
//遍历Activity所有方法
for(Method method:methods){
//获取方法上所有的注解
Annotation[] annnotions = method.getAnnotations();
for(Annotation annotation:annnotions){
//获取注解annotionType onClick OnLongClick
Class<?> annotionType = annotation.annotationType();
//获取注解的注解 onClick注解上面的EventBase
EventBase eventBase = annotionType.getAnnotation(EventBase.class);
if(eventBase==null){
continue;
}
//开始获取事件三要素 1 通过反射注入进去
String listenerSetter = eventBase.listenerSetter();
//2 得到listenrType-------->View.OnClickListener.class
Class<?> listenerType = eventBase.listenerType();
//3 callmethod----->onClick
String callMethod = eventBase.callBackMethod();
//方法名 与方法Method的对应关系
Map<String,Method> methodMap = new HashMap<>();
methodMap.put(callMethod,method);//eg:key:onClick(自己定义的)======value:MainActivity.onClick(Activity中的)
try {
Method valueMethod = annotionType.getDeclaredMethod("value");
int[] viewIds = (int[]) valueMethod.invoke(annotation);
for(int viewId:viewIds){
//1 通过反射拿到View
Method findViewById = clazz.getMethod("findViewById",int.class);
View view = (View) findViewById.invoke(context,viewId);
if(view==null){
continue;
}
//eg:setOnClickListener(View.OnClickListener.class)
Method setOnClickListener = view.getClass().getMethod(listenerSetter,listenerType);
ListenerInvocationHandler handler = new ListenerInvocationHandler(context,methodMap);
//proxy 已经实现了listenerType接口
Object proxy = Proxy.newProxyInstance(
listenerType.getClassLoader(),
new Class[]{listenerType},handler);
//view.setOnClickListener(new View.OnClickListener(){
//@Override
// public void onClick(View v) {
// }
// });
// }) 接口里的方法有proxy来处理
setOnClickListener.invoke(view,proxy);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
4.3 使用注入事件
@onClick(R.id.btn_event_onclick)
public void click(View view){
Toast.makeText(this,"单击",Toast.LENGTH_LONG).show();
}
@OnLongClick(R.id.btn_event_onclick)
public boolean onLongClick(View v){
Toast.makeText(this,"长按",Toast.LENGTH_LONG).show();
return true;
}