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;
    }
}

 

posted @ 2020-04-16 16:01  逍遥散人95  阅读(569)  评论(0编辑  收藏  举报