• Android IOC 注解技术


    手写IOC 注解框架,由于代码中有详细注释,这里就基本只上代码。

    1. 先写一个setContentView()、findViewById()、onClick()事件注解:

     1 //----------setContentView()注解----------
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 @Target(ElementType.TYPE) //将注解写到类上面
     9 @Retention(RetentionPolicy.RUNTIME) //程序运行时执行
    10 public @interface ContentView {
    11     int value() default -1;
    12 }
    13 
    14 //----------findViewById()注解----------
    15 
    16 import java.lang.annotation.ElementType;
    17 import java.lang.annotation.Retention;
    18 import java.lang.annotation.RetentionPolicy;
    19 import java.lang.annotation.Target;
    20 
    21 @Target(ElementType.FIELD)
    22 @Retention(RetentionPolicy.RUNTIME)
    23 public @interface ViewInject {
    24     int value() default -1;
    25 }
    26 
    27 //----------onClick()事件注解----------
    28 
    29 import java.lang.annotation.ElementType;
    30 import java.lang.annotation.Retention;
    31 import java.lang.annotation.RetentionPolicy;
    32 import java.lang.annotation.Target;
    33 
    34 /**
    35  * 该注解在另一个注解上面使用
    36  */
    37 @Target(ElementType.ANNOTATION_TYPE)
    38 @Retention(RetentionPolicy.RUNTIME)
    39 public @interface EventBase {
    40 
    41     // 1.setOnClickListener 订阅
    42     String listenerSetter();
    43 
    44     // 2.new.View.OnClickListener() 事件
    45     Class<?> listenerType();
    46 
    47     // 3.onClick(View v) 事件处理
    48     String callbackMethod();
    49 }
    50 
    51 import android.view.View;
    52 
    53 import java.lang.annotation.ElementType;
    54 import java.lang.annotation.Retention;
    55 import java.lang.annotation.RetentionPolicy;
    56 import java.lang.annotation.Target;
    57 
    58 @Target(ElementType.METHOD)
    59 @Retention(RetentionPolicy.RUNTIME)
    60 @EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class, callbackMethod = "onClick")
    61 public @interface OnClick {
    62     int[] value() default -1;
    63 }

    2.定义一个公共类 InjectUtils.java 这个类相当也是第三方,需要在BaseActivity中声明。

    import com.sprsoft.iocframe.annotation.ContentView;
    import com.sprsoft.iocframe.annotation.EventBase;
    import com.sprsoft.iocframe.annotation.ViewInject;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 这就是第三方
     */
    public class InjectUtils {
    
        public static void inject(Object context) {
            //注入的功能在这里完成
            injectLayout(context);
            injectView(context);
            injectClick(context);
        }
    
        /**
         * 布局
         *
         * @param context
         */
        private static void injectLayout(Object context) {
            Class<?> clazz = context.getClass();
            ContentView contentView = clazz.getAnnotation(ContentView.class);
            if (contentView != null) {
                int layoutID = contentView.value();
                //反射执行setContentView(this);
                try {
                    Method method = context.getClass().getMethod("setContentView", int.class);
                    method.invoke(context, layoutID);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 控件注入
         *
         * @param context
         */
        private static void injectView(Object context) {
            Class<?> aClass = context.getClass();
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                ViewInject viewInject = field.getAnnotation(ViewInject.class);
                if (viewInject != null) {
                    int valueId = viewInject.value();
                    try {
                        Method method = aClass.getMethod("findViewById", int.class);
                        View view = (View) method.invoke(context, valueId);
                        field.setAccessible(true);
                        field.set(context, view);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        /**
         * 事件
         * 涉及事件三要素:事件源、事件、事件处理
         *
         * @param context
         */
        private static void injectClick(Object context) {
            Class<?> clazz = context.getClass();
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                //这就写死了
                //OnClick annotation = method.getAnnotation(OnClick.class);
                Annotation[] annotations = method.getAnnotations();
                for (Annotation annotation : annotations) {
                    //得到OnClick上一级的EventBase
                    Class<?> annotionClass = annotation.annotationType();
                    EventBase eventBase = annotionClass.getAnnotation(EventBase.class);
                    //如果没有EventBase则当前方法不是一个事件处理程序
                    if (eventBase == null) {
                        continue;
                    }
                    //否则是事件处理回调的函数,是的开始得到相关的事件要素
                    //1.订阅关系
                    String listenerSetter = eventBase.listenerSetter();
                    //2.事件
                    Class<?> listenerType = eventBase.listenerType();
                    //3.事件处理程序
                    String callbackMethod = eventBase.callbackMethod();
                    try {
                        //反射得到ID 根据ID得到相应VIEW
                        Method valueMethod = annotionClass.getDeclaredMethod("value");
                        int[] viewId = (int[]) valueMethod.invoke(annotation);
                        //对每一个ID进行事件绑定
                        for (int id : viewId) {
                            //找到ID对应的对象
                            Method findId = clazz.getMethod("findViewById", int.class);
                            View view = (View) findId.invoke(context, id);
                            if (view == null) {
                                continue;
                            }
                            //得到ID对应的View以后,开始在View上执行监听
                            //用代理执行View.OnClickListener()方法
                            //需要执行activity上的OnClick方法
                            ListenerInvocationHandler listenerHandler = new ListenerInvocationHandler(context, method);
                            //去View.OnClickListener() == listenerType代理这个接口
                            Object proxy = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, listenerHandler);
                            //执行方法
                            Method onClickMethod = view.getClass().getMethod(listenerSetter, listenerType);
                            onClickMethod.invoke(view, proxy);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    3.去实现一个事件代理类(ListenerInvocationHandler)

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 事件代理类
     * public void onClick(View v){}
     */
    public class ListenerInvocationHandler implements InvocationHandler {
        private Object activity;
        private Method activityMethod;
    
        public ListenerInvocationHandler(Object activity, Method activityMethod) {
            this.activity = activity;
            this.activityMethod = activityMethod;
        }
    
        /**
         * 点击按钮后执行这个方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //在这里调用被注解的onClick方法
            return activityMethod.invoke(activity, args);
        }
    }
    

      

    4. BaseActivity.java中初始化

    import android.content.Intent;
    import android.os.Bundle;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import com.sprsoft.iocframe.utils.InjectUtils;
    
    public class BaseActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            InjectUtils.inject(this);
        }
    
        /**
         * 根据传入的Class
         *
         * @param pClass
         */
        public void openNewActivity(Class<?> pClass) {
            Intent _Intent = new Intent();
            _Intent.setClass(this, pClass);
            startActivity(_Intent);
        }
    }
    

     5.实现上面的以后下来就开始调用了。

    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import com.sprsoft.iocframe.annotation.ContentView;
    import com.sprsoft.iocframe.annotation.OnClick;
    import com.sprsoft.iocframe.annotation.OnLongClick;
    import com.sprsoft.iocframe.annotation.ViewInject;
    import com.sprsoft.practical.R;
    import com.sprsoft.practical.base.BaseActivity;
    
    /**
     * IOC 注入框架设计(注解)
     */
    @ContentView(R.layout.activity_ioc)
    public class IOCActivity extends BaseActivity {
    
        @ViewInject(R.id.edt_old_password)
        EditText edtOldPassword;
    
        @ViewInject(R.id.edt_new_password)
        EditText edtNewPassword;
    
        @ViewInject(R.id.edt_reset_password)
        EditText edtResetPassword;
    
        @ViewInject(R.id.btn_password_save)
        Button btnPasswordSave;
    
        @ViewInject(R.id.btn_password_cancel)
        Button btnPasswordCancel;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Toast.makeText(this, btnPasswordSave.getText().toString(), Toast.LENGTH_SHORT).show();
        }
    
        @OnClick({R.id.btn_password_save, R.id.btn_password_cancel})
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_password_cancel:
                    Toast.makeText(this, "取消成功", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.btn_password_save:
                    Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    
        @OnLongClick({R.id.btn_password_save, R.id.btn_password_cancel})
        public boolean onLongClick(View view) {
            switch (view.getId()) {
                case R.id.btn_password_cancel:
                    Toast.makeText(this, "长按取消成功", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.btn_password_save:
                    Toast.makeText(this, "长按保存成功", Toast.LENGTH_SHORT).show();
                    break;
            }
            return true;
        }
    }
  • 相关阅读:
    java接口请求超时处理方法
    Spring Cloud GateWay 服务网关
    Mysql中on条件和where条件的使用总结
    Elasticsearch之javaAqi
    Elasticsearch—CRUD
    ElasticSearch的版本控制和Mapping创建
    cmd定时任务计划
    CSS简介及使用
    html简介及应用
    Python基础(十五)-IO模型
  • 原文地址:https://www.cnblogs.com/xiaoyao095/p/12713493.html
Copyright © 2020-2023  润新知