写一套IOC注解框架

news/2024/7/8 3:09:47

首先控件属性注入

//@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();
    }
}

http://www.niftyadmin.cn/n/3648886.html

相关文章

乐视揭秘Android5.0手机APP安装失败真相

Android5 0正在成为手机行业的新趋势&#xff0c;越来越多的手机厂商开始推出Android5 0系统的新一代手机。Android5.0正在成为手机行业的新趋势&#xff0c;越来越多的手机厂商开始推出Android5.0系统的新一代手机。乐视更是一口气推出三大旗舰手机&#xff0c;三款手机搭载的…

如何在CentOS 7上安装和使用TimescaleDB

The author selected the Computer History Museum to receive a donation as part of the Write for DOnations program. 作者选择“ 计算机历史博物馆”作为“ Write for DOnations”计划的一部分接受捐赠。 介绍 (Introduction) Many applications, such as monitoring sys…

android 解决APN问题

android4.0之后&#xff0c;需要系统签名&#xff0c;并把apk放在system/app下面 [html] view plaincopy <uses-permission android:name"android.permission.ACCESS_NETWORK_STATE" > </uses-permission> <uses-permission android:name&q…

react hooks使用_使用Hooks动态加载React组件

react hooks使用Dynamic sites need flexibility. Flexibility results in more code. More code means increased maintenance time. How can we keep our sites maintainable and fast? 动态站点需要灵活性。 灵活性导致更多代码。 更多代码意味着增加维护时间。 我们如何保…

收集崩溃信息上传服务器

直接贴完整代码&#xff0c;详细介绍&#xff0c;里面有做介绍 public class ExceptionCrashHanlder implements UncaughtExceptionHandler {private static final String TAG ExceptionCrashHanlder.class.getSimpleName();private static ExceptionCrashHanlder instance;p…

python中的异步请求库_如何开始使用Python中的请求库

python中的异步请求库介绍 (Introduction) In many web apps, it’s normal to connect to various third-party services by using APIs. When you use these APIs you can get access to data like weather information, sports scores, movie listings, tweets, search engi…

从“奥运门票网站800万访问量”想到的成本、质量、进度、风险等关系

看到这个新闻后颇有一番滋味&#xff0c;更体验到我一直关注的软件性能着实无处不在&#xff0c;这个案例也确实值得我们好好反思一下。不知道网友们有没有报名参加国际日语考试的——这个网站每年05年前都有人不能报名&#xff0c;因为报名人数太多&#xff0c;所以报名当日大…

Android Contacts (一)ContentResolver query 参数详解

1.获取联系人姓名 一个简单的例子&#xff0c;这个函数获取设备上所有的联系人ID和联系人NAME。 [java] view plaincopy public void fetchAllContacts() { ContentResolver contentResolver this.getContentResolver(); Cursor cursor contentResolver.query(an…