首先我们说说java元注解
@Target(注解的作用目标) @Retention(注解的保留位置)
@Ducument(说明该注解将包含在javadoc中) @Inherited(说明子类可以继承父类中的该注解)
1, @Target(ElmentType.Type) //同下
ElementTypeTYPE 类、接口(包括注释类型)或枚举声明
ElementTypeFIELD 字段声明(包括枚举常量)
ElementTypeMETHOD 方法声明
ElementTypePARAMETER 参数声明
ElementTypeCONSTRUCTOR 构造方法声明
ElementTypeLOCAL_VARIABLE 局部变量声明
ElementTypeANNOTATION_TYPE 注释类型声明
ElementTypePACKAGE 包声明
2,@Retention
@Retention(RetentionPolicy.SOURCE)//注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)//注解class会字节码中,运行时无法获取,(默认策略)
@Retention(RetentionPolicy.RUNTIME)//注解会在class字节码中存在,运行时可以通过反射获取
框架实现
得进入正题了,Android IOC框架,其实主要就是帮大家注入所有的控件,布局文件什么的。如果你用过xUtils,afinal类的框架,你肯定不陌生~
MainActivity
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.tv_text)
private TextView mTextView;
@OnClick({R.id.btn})
public void onClick(View view) {
Toast.makeText(this, "按下", Toast.LENGTH_SHORT).show();
}
@OnLongClick({R.id.btn_long})
public boolean onLongClick(View view) {
Toast.makeText(this, "长按", Toast.LENGTH_SHORT).show();
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewInjectUtils.inject(this);
mTextView.setText("inject");
}
}
ContentView
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int value();
}
ViewInject
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
click事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter = "setOnClickListener",
listenerType = View.OnClickListener.class,
callBackMethod = "onClick")
public @interface OnClick
{
/**
* 进行设置点击事件
* @return
*/
int[] value();
}
longclick事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventBase(listenerSetter = "setOnLongClickListener",
listenerType = View.OnLongClickListener.class,callBackMethod = "onLongClick")
public @interface OnLongClick {
int[] value() default -1;
}
ContentView注入
/**
* 注入ContentV
*
* @param activity
*/
private static void injectContentView(AppCompatActivity activity) {
Class<? extends AppCompatActivity> mClass = activity.getClass();
ContentView contentView = mClass.getAnnotation(ContentView.class);
if (contentView != null) {
int layoutId = contentView.value();
try {
Method method = mClass.getMethod(METHOD_SET_CONTENTVIEW, int.class); //int.class 是一个引用
method.setAccessible(true);
method.invoke(activity, layoutId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
View注入
/**
* @param activity
*/
private static void injectViews(AppCompatActivity activity) {
Class<? extends AppCompatActivity> mClass = activity.getClass();
//拿到所有变量
Field[] mField = mClass.getDeclaredFields();
for (Field field : mField) {
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
int id = viewInject.value();
if (id != -1) {
try {
Method method = mClass.getMethod(METHOD_FIND_VIEW_BY_ID, int.class);
field.setAccessible(true);
Object view = method.invoke(activity, id);
field.set(activity, view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Event事件注入
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
/**
* 设置监听的方法
* @return
*/
String listenerSetter();
/**
* 事件类型
* @return
*/
Class<?> listenerType();
/**
* 回调方法
* 事件被触发后,执行回调方法名称
* @return
*/
String callBackMethod();
}
/**
* 注入点击和长按事件
* @param context
*/
private static void injectEvents(AppCompatActivity context) {
Class<?> clazz = context.getClass();
Method[] methods = clazz.getDeclaredMethods();
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;
}
String listenerSetter = eventBase.listenerSetter();
Class<?> listenerType = eventBase.listenerType();
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) {
//通过反射拿到View
Method findViewById = clazz.getMethod("findViewById", int.class);
View view = (View) findViewById.invoke(context, viewId);
if (view == null) {
continue;
}
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);
//接口里的方法有proxy来处理
setOnClickListener.invoke(view, proxy);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
ListenerInvocationHandler
public class ListenerInvocationHandler implements InvocationHandler {
//activity 真实对象
private Context context;
private Map<String, Method> methodMap;
public ListenerInvocationHandler(Context context, Map<String, Method> methodMap) {
this.context = context;
this.methodMap = methodMap;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
//决定是否需要进行代理
Method metf = methodMap.get(name);
if (metf != null) {
return metf.invoke(context, args);
} else {
return method.invoke(proxy, args);
}
}
}
网友评论