Android架构设计05-基于IOC的布局,控件,事件注入

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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值