首先控件属性注入
//@Target(ElementType.FIELD) 代表Annotion的值 FIELD属性 TYPE类上 METHOD方法 CONSTRUCTOR构造函数
@Target(ElementType.FIELD)
//@Retention(RetentionPolicy.RUNTIME) 运行时生效 CLASS编译时生效 SOURCE源码资源
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewById {
int value();
}
public class ViewUtils {
public static void inject(Activity activity) {
inject(new ViewFinder(activity), activity);
}
// 兼容View
public static void inject(View view) {
inject(new ViewFinder(view), view);
}
// 兼容Fragment
public static void inject(View view, Object object) {
inject(new ViewFinder(view), object);
}
private static void inject(ViewFinder viewFinder, Object object) {
injectFiled(viewFinder, object);
injectEvent(viewFinder, object);
}
// 注入事件
private static void injectEvent(ViewFinder viewFinder, Object object) {
}
/**
* 注入属性
*/
private static void injectFiled(ViewFinder viewFinder, Object object) {
// object --> activity or fragment or view 是反射的类
// viewFinder --> 只是一个view的findViewById的辅助类
// 1. 获取所有的属性
Class<?> clazz = object.getClass();
// 获取所有属性包括私有和公有
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 2. 获取属性上面ViewById的值
ViewById viewById = field.getAnnotation(ViewById.class);
if (viewById != null) {
// 获取ViewById属性上的viewId值
int viewId = viewById.value();
// 3. 通过findViewById获取View
View view = viewFinder.findViewById(viewId);
if (view != null) {
// 4. 反射注入View属性
// 设置所有属性都能注入包括私有和公有
field.setAccessible(true);
try {
field.set(object, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
throw new RuntimeException("Invalid @ViewInject for "
+ clazz.getSimpleName() + "." + field.getName());
}
}
}
}
}
/**
* 注解帮组类
*/
public class ViewFinder {
private Activity mActivity;
private View mView;
public ViewFinder(Activity activity) {
this.mActivity = activity;
}
public ViewFinder(View view) {
this.mView = view;
}
public View findViewByld(int viewld){
return mActivity!=null?mActivity.findViewById(viewld):mView.findViewById(viewld);
}
}
点击事件注入
//@Target(ElementType.FIELD) 代表Annotion的值 FIELD属性 TYPE类上 METHOD方法 CONSTRUCTOR构造函数
@Target(ElementType.METHOD)
//@Retention(RetentionPolicy.RUNTIME) 运行时生效 CLASS编译时生效 SOURCE源码资源
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
int[] value();
}
// 事件注入
private static void injectEvent(ViewFinder viewFinder, Object object) {
// 1.获取所有方法
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
// 2.获取方法上面的所有id
for (Method method : methods) {
OnClick onClick = method.getAnnotation(OnClick.class);
if (onClick != null) {
int[] viewIds = onClick.value();
if (viewIds.length > 0) {
for (int viewId : viewIds) {
// 3.遍历所有的id 先findViewById然后 setOnClickListener
View view = viewFinder.findViewById(viewId);
if (view != null) {
view.setOnClickListener(new DeclaredOnClickListener(method, object));
}
}
}
}
}
}
private static class DeclaredOnClickListener implements View.OnClickListener {
private Method mMethod;
private Object mHandlerType;
public DeclaredOnClickListener(Method method, Object handlerType) {
mMethod = method;
mHandlerType = handlerType;
}
@Override
public void onClick(View v) {
// 4.反射执行方法
mMethod.setAccessible(true);
try {
mMethod.invoke(mHandlerType, v);
} catch (Exception e) {
e.printStackTrace();
try {
mMethod.invoke(mHandlerType, null);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
public class MainActivity extends AppCompatActivity {
@ViewById(R.id.icon)
private ImageView mIconIv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
mIconIv.setImageResource(R.drawable.icon);
}
@OnClick(R.id.icon)
private void onClick(View view) {
int i = 2 / 0;
Toast.makeText(this, "图片点击了"+i, Toast.LENGTH_LONG).show();
}
}
使用起来和xutils类似,方法和属性可以私有,但是有一点我们在Onclick点击事件的方法里面无论做什么操作都是不会报错的,所以如果发现bug需要留意警告日志,这不是坑嗲吗?其实在我们的开发过程给用户或者老板玩的时候我们最怕的是闪退,现在我们就算有Bug也不会出现闪退的情况只是调试的时候需要留意警告日志还是蛮不错的。
扩展动态检测网络状态
//@Target(ElementType.FIELD) 代表Annotion的值 FIELD属性 TYPE类上 METHOD方法 CONSTRUCTOR构造函数
@Target(ElementType.METHOD)
//@Retention(RetentionPolicy.RUNTIME) 运行时生效 CLASS编译时生效 SOURCE源码资源
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNet {
}
/**
* 判断是否有网
*/
private static boolean networkAvailable(Context context) {
try {
ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager
.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
return networkInfo.isAvailable();
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static void injectMethod(ViewFinder finder, Object object) {
//1.获取类里面所有方法
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
OnClick onClick = method.getAnnotation(OnClick.class);
//2.获取onClick里面的值(R.id.tv)
if (onClick != null) {
int[] values = onClick.value();
for (int value : values) {
//3.findviewByld获取view
View view = finder.findViewByld(value);
//扩展功能,检测网络
//判断是否添加了检查网络
boolean isCheckNet = method.getAnnotation(CheckNet.class) != null;
//4.设置点击事件_view.setonClickListener
if (view != null) {
view.setOnClickListener(new DeclaredOnClickListener(method, object, isCheckNet));
}
}
}
}
}
private static class DeclaredOnClickListener implements View.OnClickListener {
private Method mMethod;
private Object mObject;
private boolean mIsCheckNet;
public DeclaredOnClickListener(Method method, Object object, boolean isCheckNet) {
this.mMethod = method;
this.mObject = object;
this.mIsCheckNet = isCheckNet;
mMethod.setAccessible(true);
}
//5.反射执行方法
@Override
public void onClick(View v) {
if (mIsCheckNet) {//是否添加注解
if (!networkAvailable(v.getContext())) {//判断当前是否有网,没有网直接retrun;
Toast.makeText(v.getContext(), "亲,请检查你的网络,谢谢", Toast.LENGTH_SHORT).show();
return;
}
}
try {
mMethod.invoke(mObject, v);
} catch (Exception e) {
e.printStackTrace();
try {
mMethod.invoke(mObject, null);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
public class MainActivity extends AppCompatActivity {
@ViewById(R.id.icon)
private ImageView mIconIv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
mIconIv.setImageResource(R.drawable.icon);
}
@OnClick(R.id.icon)
@CheckNet // 检测网络
private void onClick(View view) {
Toast.makeText(this, "图片点击了", Toast.LENGTH_LONG).show();
}
}