在第一次潭州教育的公开课上接触了这个框架的讲解,我动手研究了一下,结果一出手就停不下来,先后被我碰上了(Glow公司的技术博客——动态Android编程 )、从几个大牛的博客(学到了github pages + Jekyll 免费制作博客网站)
我发现不写博客,很多东西就会忘记(代码如何上传到jcenter我已经忘记了)
Just Do it!真的会有意想不到的收获!
1. IOC概念介绍
http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075.html我是从这边文章学习的IOC概念的,写的浅显易懂
@ContentViewInject(R.layout.activity_main)
public class MainActivity extends AppCompatActivity
@Target(ElementType.TYPE)// 使用对象:类
@Retention(RetentionPolicy.RUNTIME)// 生命范围:运行期
public @interface ContentViewInject {
int value();// 存放布局id
}
private static void injectLayout(Activity context) {
try {
// UIClz
Class extends Context> uiClass = context.getClass();
// 类上的注解
ContentViewInject annotation = uiClass.getAnnotation(ContentViewInject.class);
if (annotation != null) {
// 注解中的layout id值
int value = annotation.value();
// 通过反射使用activity中的setContentView方法进行 布局设置
// 局限性:这个方法仅仅适用于activity
Method setContentView = uiClass.getMethod("setContentView", int.class);
setContentView.invoke(context, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@ViewInject(R.id.textView)
TextView textView;
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TurInject.bind(this);
textView.setText("徕帝嘎嘎");
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
private static void injectViews(Context context) {
try {
Class extends Context> uiClass = context.getClass();
// 获取成员变量
Field[] fields = uiClass.getDeclaredFields();
for (Field field : fields) {
ViewInject annotation = field.getAnnotation(ViewInject.class);
if (annotation != null) {
int value = annotation.value();
Method findViewById = uiClass.getMethod("findViewById", int.class);
Object invoke = findViewById.invoke(context, value);
// 设置允许访问
field.setAccessible(true);
field.set(context, invoke);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@ClickEvent(value = {R.id.textView}, type = View.OnClickListener.class)
public void ccClick(View view) {
Toast.makeText(getBaseContext(), "ccClick", Toast.LENGTH_LONG).show();
}
@ClickEvent(value = {R.id.textView}, type = View.OnLongClickListener.class)
public void longClick(View view) {
Toast.makeText(getBaseContext(), "longClick", Toast.LENGTH_LONG).show();
}
public static void injectMethod(final Context context) {
try {
Class extends Context> uiClass = context.getClass();
// 获取所有的方法
Method[] methods = uiClass.getMethods();
for (final Method method : methods) {
ClickEvent annotation = method.getAnnotation(ClickEvent.class);
// 塞选含有ClickEvent注解的方法
if (annotation != null) {
int[] values = annotation.value();
Class type = annotation.type();
// 拿到控件
for (int viewId : values) {
// 初始化控件
Method findViewById = uiClass.getMethod("findViewById", int.class);
// view
final Object viewObj = findViewById.invoke(context, viewId);
Class> viewClass = viewObj.getClass();
// setOnClickListener/setOnLongClickListener等等
String viewSetMethodName = "set" + type.getSimpleName();
Method viewMethod = viewClass.getMethod(viewSetMethodName, type);
// 动态代理就是针对 任意 一个对象的接口方法的 管理/拦截/AOP
ViewEventInvocationHandler viewEventInvocationHandler = new ViewEventInvocationHandler(context, method);
// type.getClassLoader : 类加载器 new Class[]{type} : type为接口类
Object eventInterfaceInstance = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, viewEventInvocationHandler);
// 动态代理 OnClickListener 中的
// 执行了setOnClickListener这个方法,那么在响应这个参数OnClickListener接口中的,onclick方法的时候会响应InvocationHandler中的invoke方法
viewMethod.invoke(viewObj, eventInterfaceInstance);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static class ViewEventInvocationHandler implements InvocationHandler {
private Context context;
private Method contentMethod;
public ViewEventInvocationHandler(Context context, Method contentMethod) {
this.context = context;
this.contentMethod = contentMethod;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method 为OnClickListener 中的 onClick
// 系统调用参数接口中的 onClick方法的时候,会响应这个方法
// 响应这个方法的时候我们需要响应(activity中被ClickEvent标记过的方法)
// contentMethod 为activity中被 ClickEvent标记过的方法
contentMethod.invoke(context, args);
return true;
}
}
知乎——代理、动态代理
动态代理的缺憾:Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏
到这里呢,XUtils的布局注入、控件注入、事件注入就全部介绍完了!