1.概述
什么是IOC,控制反转(Inversion of Control,英文缩写为IOC),其实就是反射加注解,Android IOC框架,其实主要就是帮大家注入所有的控件,布局文件什么的。如果你用过xUtils,Butterkinfe等框架,你肯定不陌生~
2.框架实现
大家有时间可以去看一下xUtils,Butterkinfe源码,这里不过多介绍,就直接开始了,我采用的方式是反射加注解和Xutils类似
思路:
1.定义属性注解,点击事件注解,网络检查注解。
2.通过反射获取类的所有属性,遍历获取属性上的注解 ViewById 找到对应的value值,进行处理
3.通过反射获取类的所有方法,遍历获取方法上的注解 OnClick CheckNet 找到对应的value值,设置点击事件等,进行处理
2.1.定义属性控件注解
/**
* Created by ych on 2019/8/12.
* Description: View属性注解的Annotation
*/
//@Target(ElementType.FIELD) 表示Annotation的位置 FIELD属性上 METHOD方法上 TYPE类上 CONSTRUCTOR构造方法上
@Target(ElementType.FIELD)
//@Retention(RetentionPolicy.CLASS) 表示什么时候生效 CLASS编译时 RUNTIME运行时 SOURCE源码资源
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewById {
//表示可以 @ViewById(R.id.text_tv)
int value();
}
/**
* Created by ych on 2019/8/12.
* Description: 使用在Activity 自定义View Fragment
*/
public class ViewUtils {
/**
* 目前使用Activity上
*
* @param activity
*/
public static void inject(Activity activity) {
inject(new ViewFinder(activity), activity);
}
/**
* 自定义View上
*
* @param view
*/
public static void inject(View view) {
inject(new ViewFinder(view), view);
}
/**
* Fragment上
*
* @param view
* @param object 表示Fragment
*/
public static void inject(View view, Object object) {
inject(new ViewFinder(view), object);
}
/**
* 兼容上边三个
* @param finder
* @param object 表示反射时需要执行的类 也就是Activity Fragment View
*/
public static void inject(ViewFinder finder, Object object) {
injectFiled(finder, object);
}
/**
* 注入属性
* @param finder
* @param object
*/
private static void injectFiled(ViewFinder finder, Object object) {
//1.获取类里面所有属性
Class<?> clazz = object.getClass();
//获取类中所有属性,包括私有和公有
Field[] fields = clazz.getDeclaredFields();
//2.获取ViewById的value
for (Field field : fields) {
ViewById viewById = field.getAnnotation(ViewById.class);
if (viewById != null) {
int viewId = viewById.value();
//3.findViewById找到View
View view = finder.findViewById(viewId);
if (view!=null){
//能够注入所有修饰符 private public
field.setAccessible(true);
//4.动态注入到找到的View
try {
/**
* object:代表我们的要注入的View (Activity ,Fragment, View)
* view:就是我们的要注解View (TextView,ImageView等等)
*/
field.set(object,view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
2.2.定义点击事件注解+网络检查注解
/**
* Created by ych on 2019/8/12.
* Description: View点击事件注解Annotation
*/
//注解作用在方法上
@Target(ElementType.METHOD)
//注解什么时候调用 RUNTIME运行时调用
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
//方法上可以多个
int[] value();
}
/**
* Created by ych on 2019/8/12.
* Description: View网络检查注解的Annotation
*/
//@Target(ElementType.FIELD) 表示Annotation的位置 FIELD属性上 METHOD方法上 TYPE类上 CONSTRUCTOR构造方法上
@Target(ElementType.METHOD)
//@Retention(RetentionPolicy.CLASS) 表示什么时候生效 CLASS编译时 RUNTIME运行时 SOURCE源码资源
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNet {
}
/**
* 注入事件
* @param finder
* @param object
*/
private static void injectEvent(ViewFinder finder, Object object) {
//1.获取类里面所有方法
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
//2.循环遍历所有方法 获取带注解为OnClick的value值
for (Method method : methods) {
OnClick click = method.getAnnotation(OnClick.class);
if (click!=null){
int[] viewIds = click.value();
//3.findViewById找到对应的OnClick
for (int viewId : viewIds) {
View view = finder.findViewById(viewId);
//拓展功能,是否需要检查网络 不为空检查网络
boolean isCheckNet = method.getAnnotation(CheckNet.class)!=null;
//4.设置点击事件setOnClickListent
view.setOnClickListener(new DeclaredOnClickListener(method,object,isCheckNet));
}
}
}
}
public static class DeclaredOnClickListener implements View.OnClickListener{
private Method mMethod;
private Object mObject;
private Boolean isCheckNet;
/**
* @param method 方法
* @param object 哪个页面上Activity
*/
public DeclaredOnClickListener(Method method, Object object,boolean isCheckNet) {
this.mMethod = method;
this.mObject = object;
this.isCheckNet = isCheckNet;
}
@Override
public void onClick(View v) {
//需不需要检查网络
if (isCheckNet){
if (!networkAvailable(v.getContext())){
//这里写死是有问题的,需要配置
Toast.makeText(v.getContext(),"亲,您的网络不太给力",Toast.LENGTH_SHORT).show();
return;
}
}
mMethod.setAccessible(true);
try {
//5.反射执行该方法
mMethod.invoke(mObject,v);
} catch (Exception e) {
e.printStackTrace();
try {
mMethod.invoke(mObject,null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
/**
* 判断网络
* @param context
* @return
*/
public static boolean networkAvailable(Context context) {
try {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
return true;
}
}
}catch (Exception e){
e.printStackTrace();
}
return false;
}
3.使用
public class TestActivity extends AppCompatActivity {
private final String TAG = "TestActivity";
//注解注入
@ViewById(R.id.iv_skin)
private ImageView mIvskin;
@ViewById(R.id.btn_skin)
private Button mBtnskin;
@ViewById(R.id.btn_call)
private Button mBtncall;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
}
//点击事件和网络注解
@OnClick({R.id.iv_skin,R.id.btn_skin,R.id.btn_call})
@CheckNet
public void onClick(View view) {
switch (view.getId()){
case R.id.iv_skin:
Toast.makeText(this,"图片",Toast.LENGTH_SHORT).show();
break;
case R.id.btn_skin:
Toast.makeText(this,"换肤",Toast.LENGTH_SHORT).show();
break;
case R.id.btn_call:
Toast.makeText(this,"打电话",Toast.LENGTH_SHORT).show();
break;
}
}
}
网友评论