











新建model 结构图

代码如下
/**
* 时间:2019/10/30 15:29
* 描述:Target 是目标的意思 也叫该注解作用在XXX上的意思 ElementType.TYPE 作用于接口类枚举之上
* ANNOTATION_TYPE 作用在注解之上
*/
@Target(ElementType.TYPE)//
@Retention(RetentionPolicy.RUNTIME)//jvm加载时通过反射获取注解的值
public @interface ContentView {
//int 类型的布局
int value();
}
/**
* 时间:2019/10/30 16:50
* 描述:
*/
@Target(ElementType.ANNOTATION_TYPE)//改注解作用在其他注解之上
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
//1,监听的方法名,setOnClickListener()
String listenerSetter();
//2,监听的对象,View.OnClickListener()
Class<?> listenerType();
//3,回调方法名,OnClick(View v)
String callBackListener();
}
@Target(ElementType.FIELD)//在属性之上
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
//int 类型的控件(R.id.xxx)
int value();
}
@Target(ElementType.METHOD)//方法之上
@Retention(RetentionPolicy.RUNTIME)
@EventBase(listenerSetter = "setOnClickListener",listenerType = View.OnClickListener.class,callBackListener = "onClick")
public @interface OnClick {
int[] value();//点击ID可能有很多个
}
/**
* 描述:注入管理
*/
public class InjectManager {
public static void inject(Activity activity) {
//布局注入
injectLayout(activity);
//控件注入
injectViews(activity);
//事件注入
injectEvents(activity);
}
//布局注入
private static void injectLayout(Activity activity) {
//获取类
Class<? extends Activity> clazz = activity.getClass();
//获取类的注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (null != contentView) {
int layoutId = contentView.value();
//方式一
//activity.setContentView(layoutId);
try {
//方式二:反射的技术
//1,获取指定的方法 setContentView()
Method method = clazz.getMethod("setContentView", int.class);//获取本类和父类的所有公共方法
//2,执行方法
method.invoke(activity, layoutId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//控件注入
private static void injectViews(Activity activity) {
//获取类
Class<? extends Activity> clazz = activity.getClass();
//获取所有属性(包括私有属性)
Field[] fields = clazz.getDeclaredFields();
//遍历 拿到每个属性
for (Field field : fields) {
// 拿到每个属性额注解
InjectView injectView = field.getAnnotation(InjectView.class);
if (null != injectView) {
// 拿到每个属性额注解的值 R.id.xxx
int viewId = injectView.value();
//方式一
//View view = activity.findViewById(viewId);
try {
//方式二:反射的技术
//1,获取指定的方法 findViewById()
Method method = clazz.getMethod("findViewById", int.class);//获取本类和父类的所有公共方法
//2,执行方法
Object view = method.invoke(activity, viewId);
//设置访问private私有权限(私有属性可以访问)
field.setAccessible(true);
//赋值过程 属性的值赋值给控件
field.set(activity, view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//事件注入
private static void injectEvents(Activity activity) {
//获取类
Class<? extends Activity> clazz = activity.getClass();
//获取所有方法 onResume onCreate .... 还有可能是私有的方法
Method[] methods = clazz.getDeclaredMethods();//获取当前类所有的方法,包括私有
//遍历方法
for (Method method : methods) {
//获取所有方法的注解(@Override @OnClick)
Annotation[] annotations = method.getAnnotations();//每个方法上的注解 有可能是个数组 一个方法上可能有好多个注解
//遍历该方法的所有注解 拿到我想要的注解
for (Annotation annotation : annotations) {
//获取 OnClick 注解上的注解类型
Class<? extends Annotation> annotationType = annotation.annotationType();
if (null != annotationType) {
EventBase eventBase = annotationType.getAnnotation(EventBase.class);
if (null != eventBase) {
//这时候已经可以获得事件 重要的三成员 如下
String listenerSetter = eventBase.listenerSetter();
Class<?> listenerType = eventBase.listenerType();
String callBackListener = eventBase.callBackListener();
ListenerInvocationHandler handler = new ListenerInvocationHandler(activity);
handler.addMethod(callBackListener, method);
//通过代理的方式 操作这个对象 并且中间拦截onClick方法 执行自定义方法
Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),
new Class[]{listenerType}, handler);
try {
//通过annotationType获取onClick注解的值
Method valueMethod = annotationType.getDeclaredMethod("value");
//再去执行value的方法获取注解的值
int[] viewIds = (int[]) valueMethod.invoke(annotation);
//把id循环出来再去赋值 避免没有赋值而报异常
for (int viewId : viewIds) {
//获取当前activity的view(赋值)
View view = activity.findViewById(viewId);
//获取指定的方法
Method setterMethod = view.getClass().getMethod(listenerSetter, listenerType);
//再去执行方法
setterMethod.invoke(view, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
/**
* 时间:2019/10/30 17:52
* 描述:拦截器 拦截本应该执行的回调方法 onClick() 而去执行我们自定义的方法
*/
public class ListenerInvocationHandler implements InvocationHandler {
//拉结的目标 比如需要拦截MainActivity中的方法
private Object target;
//需要拦截额对象 键值对
private HashMap<String,Method> methodHashMap = new HashMap();
public ListenerInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (null != target) {
//获取需要拦截的方法名
String methodName = method.getName();//如果是onClick 那就要做拦截
method = methodHashMap.get(methodName);//需要执行自定义的方法 show()方法
if (null != method) {
return method.invoke(target, args);
}
}
return null;
}
/**
* 添加将要拦截的方法
* @param methodName 拦截的方法 如 onClick
* @param method 执行的方法 如 show(自己定义的方法)
*/
public void addMethod(String methodName,Method method) {
methodHashMap.put(methodName, method);
}
}
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectManager.inject(this);
}
}
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
@InjectView(R.id.tv)
private TextView textView;
@Override
protected void onResume() {
super.onResume();
}
@OnClick({R.id.tv, R.id.btn, R.id.btn1})
public void show(View view) {
switch (view.getId()) {
case R.id.btn:
Toast.makeText(this, "点了btn1", Toast.LENGTH_SHORT).show();
break;
case R.id.btn1:
Toast.makeText(this, "点了btn2", Toast.LENGTH_SHORT).show();
break;
case R.id.tv:
textView.setText("哈哈哈");
Toast.makeText(this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
break;
}
}
}
布局很简单 按照自己心情来
网友评论