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