首页 > 学院 > 开发设计 > 正文

IOC框架手动实现

2019-11-08 00:37:21
字体:
来源:转载
供稿:网友

流行的注解框架是butterknife,使用注解框架主要是为了提高编码效率,尽可能地少写findviewbyid这种重复代码。注解分为编译期注解和运行时注解,butterknife是编译期注解,接下来自己实现的该框架是运行时注解。编译期注解有难度,并且不会对性能有影响。 Android中的注解反射框架包含三个部分: 1、Layout布局注解;2、view注解;3、事件注解。 框架建立分析如下: 该框架的目标是自动化下面3个工作: 1、Layout的注解解决的是activity的this.setContentView(R.layout.mainLayout),所以layout的注解的值只需要传递一个int值,同时需要将context对象传进去,那么其注解类设计如下:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface InjectLayout { int value();}

具体的方法:

PRivate static void injectLayout(Context context) throws NoSuchMethodException, InvocationTargetException, IllegalaccessException { Class clazz = context.getClass(); Method mtd_setContentView = clazz.getMethod("setContentView", int.class); Method mtd_findViewById = clazz.getMethod("findViewById", int.class); Annotation layoutAnnotation = clazz.getAnnotation(InjectLayout.class); if (layoutAnnotation != null && layoutAnnotation instanceof InjectLayout) { int layoutId = ((InjectLayout) layoutAnnotation).value(); mtd_setContentView.invoke(context, layoutId); }}

在Activity中的用法:

@InjectLayout(value=R.layout.activity_main)public class MainActivity extends BaseActivity {}

2、View注解,实现的是this.findViewById(R.id.xxx),所以其注解类只需要传递一个整型的id值。注解类设计如下:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface InjectView { int value();}

具体的方法:

private static void injectView(Context context) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class clazz = context.getClass(); Field[] fields = clazz.getDeclaredFields(); Method mtd_findViewById = clazz.getMethod("findViewById", int.class); for (Field field : fields) { Annotation[] annotations = field.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof InjectView) { int viewId = ((InjectView) annotation).value(); field.setAccessible(true); View view = (View) mtd_findViewById.invoke(context, viewId); field.set(context, view); } } }}

在activity中的用法:

@InjectView(value = R.id.button) Button myBtn;

3、方法的注解。其实指的是事件监听的注解,其形式为:

view.setOnClickListener(new View.OnClickListener(){ Public void onClick(View view){ Xxxx; } });

或者view.setOnLongClickListener();还有view.setOnTouchListener()等等 因为这个里面有匿名内部类,所以需要使用到动态代理。为了实现这个方法,需要知道是哪个view来绑定监听,所以注解需要包含R.id.xxx;需要知道监听的是view 的哪个方法,所以需要一个string来表示具体的方法名(匿名内部类listener实现的方法);在实现动态代理时,还需要知道匿名内部类的全类名,所以也需要一个Class;所以其注解类设计如下

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@EventBus(value = 1)public @interface InjectOnClick { String onClickListener(); String onClickMethod(); String bindListerMethod(); int[] bindViewId(); Class type();}

注解实现方法:

private static void injectOnClick(Context context) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException { Class clazz = context.getClass(); Method[] methods = clazz.getDeclaredMethods(); if (null == methods || methods.length == 0) return; HashMap<String, Method> methodMap = new HashMap<>(); for (Method method : methods) { //method:onClickText Annotation[] annotations = method.getAnnotations(); if (null == annotations || annotations.length == 0) continue; for (Annotation annotation : annotations) if (annotation instanceof InjectOnClick) { String onClickName = ((InjectOnClick) annotation).onClickMethod(); methodMap.put(onClickName, method); int[] viewIds = ((InjectOnClick) annotation).bindViewId(); for (int viewId : viewIds) { //Annotation eventBus = (Annotation)annotation.annotationType(); Method mtd_findViewById = clazz.getMethod("findViewById", int.class); //获取VIEW View view = (View) mtd_findViewById.invoke(context, viewId); Log.d(TAG, "injectOnClick: " + ""); //Class clazz_annoymous = Class.forName("android.view.View.OnClickListener"); Method setOnclickListener = view.getClass().getMethod(((InjectOnClick) annotation).bindListerMethod(), ((InjectOnClick) annotation).type()); Class clz = ((InjectOnClick) annotation).type(); //动态代理 XutilsInvocationHandler handler = new XutilsInvocationHandler(context, methodMap);//该类继承InvocationHandler. Object proxy = (Proxy) Proxy.newProxyInstance(context.getClassLoader(), new Class[]{clz}, handler); setOnclickListener.invoke(view, proxy); } } } }

在activity中的使用方法:

@InjectOnClick(onClickListener = "View.OnClickListener",bindListerMethod ="setOnClickListener", onClickMethod ="onClick",bindViewId = {R.id.button},type = View.OnClickListener.class) public void onButtonClick(View view){//此处的参数view,不能省略。 Log.d("liudong", "onClick: "); Toast.makeText(this,"BUTTON 被点击了",Toast.LENGTH_SHORT).show(); }

总体的使用方式是,新建一个BaseActivity extends Activity,在其onCreate()中,依次实现layout view onClick的注解。 public void onCreate(){ InjectUtils.injectLayout(this); InjectUtils.injectView(this); InjectUtils.injectOnClick(this); } 然后后续的Activity都继承该BaseActivity.


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表