Android进阶 (一)打造一套自己的IOC注解框架

首先看看效果和library的最终结构: 

Android进阶 (一)打造一套自己的IOC注解框架Android进阶 (一)打造一套自己的IOC注解框架Android进阶 (一)打造一套自己的IOC注解框架Android进阶 (一)打造一套自己的IOC注解框架

项目最终结构:

Android进阶 (一)打造一套自己的IOC注解框架

 

1.在自己的项目--->右键new moudle--->Android Library,然后新建一个class,图片上注释很详细:

Android进阶 (一)打造一套自己的IOC注解框架

Android进阶 (一)打造一套自己的IOC注解框架

Android进阶 (一)打造一套自己的IOC注解框架

2.新建MaxBind类,用于绑定当前的Activity或Fragment或者自定义的View等:

public class MaxBind {

    public static void bind(Activity activity){
        bind(new ViewFinder(activity),activity);
    }

    public static void bind(View view){
        bind(new ViewFinder(view),view);
    }

    //fragment里面使用
    public static void bind(View view,Object object){
        bind(new ViewFinder(view),object);
    }

    //兼容上面三个方法  object:反射需要执行的类
    private static void bind(ViewFinder finder,Object object){
        bindField(finder,object);//动态注入属性
        bindEvent(finder,object);//动态注入事件
    }

    private static void bindEvent(ViewFinder finder, Object object) {
        //1.获取类里面所有的方法
        Class<?> clazz = object.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        //2.获取BindOnClick的里面的value值
        for (Method method : methods){
            BindOnClick onClick = method.getAnnotation(BindOnClick.class);
            if (onClick != null){
                int[] valueIds = onClick.value();
                for (int viewId : valueIds){
                    //3.findViewById()找到View
                    View viewById = finder.findViewById(viewId);
                    //检测网络
                    boolean isCheckNet = method.getAnnotation(CheckNet.class) != null;//有没有加这个注解
                    if (viewById != null){
                        //4.view.setOnClickListener
                        viewById.setOnClickListener(new DeclaredOnClickListener(method,object,isCheckNet));
                    }
                }
            }
        }





    }

    private static void bindField(ViewFinder finder, Object object) {
        //1.获取类里面所有属性
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();//获取所有属性包括公有和私有的
        //2.获取findViewById()里面的value值
        for (Field field : fields){
            BindView bindView = field.getAnnotation(BindView.class);
            if (bindView != null){
                int id = bindView.value();//获取注解里面的id值(R.id.xxx)
                //3.findViewById()找到View
                View view = finder.findViewById(id);
                if (view != null){
                    field.setAccessible(true);//能够注入所有的修饰符(private,protected,public等)
                    //4.动态的注入找到的View
                    try {
                        field.set(object,view);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

    private static class DeclaredOnClickListener implements View.OnClickListener{

        private Object object;
        private Method method;
        private boolean isCheckNet;

        public DeclaredOnClickListener(Method method, Object object, boolean isCheckNet) {
            this.object = object;
            this.method = method;
            this.isCheckNet = isCheckNet;
        }

        @Override
        public void onClick(View v) {
            //需要检测网络?
            if (isCheckNet){
                if (!networkAvailable(v.getContext())){
                    //这里别写死,外部配置
                    Toast.makeText(v.getContext(),"当前没网",Toast.LENGTH_SHORT).show();
                    return;
                }
            }


            //最终点击会调这个方法
            try {
                method.setAccessible(true);
                //5.反射执行方法
                method.invoke(object,v);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
                try {
                    method.invoke(object,null);//防止没传入View崩掉
                } catch (IllegalAccessException | InvocationTargetException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private static boolean networkAvailable(Context context){
        ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (null != connectivity) {
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (null != info && info.isConnected()) {
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
        return false;
    }
}

3.新建ViewFinder辅助类,用于findViewById的辅助:

Android进阶 (一)打造一套自己的IOC注解框架

到这里为止,一个最基本的IOC注解框架就完成了,接下来是用法:

①:activity_ioc.xml:  就只有简单的几个控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/iocFrameLayout">
    </FrameLayout>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_gravity="center_horizontal"
        android:id="@+id/iocBtn"
        />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_gravity="center_horizontal"
        android:id="@+id/iocIv"
        android:src="@mipmap/ic_launcher"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:id="@+id/iocTv"
        android:text="测试文字"
        android:textSize="22sp"
        />

</LinearLayout>

 

②:IocActivity.class:

public class IocActivity extends AppCompatActivity {

    @BindView(R.id.iocBtn)
    Button iocBtn;
    @BindView(R.id.iocIv)
    private ImageView iocIv;
    @BindView(R.id.iocTv)
    protected TextView iocTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ioc);
        MaxBind.bind(this);
        iocBtn.setText("佛祖保佑,永无BUG");
    }

    @BindOnClick({R.id.iocBtn,R.id.iocIv})
    private void Click(View view){
        switch (view.getId()){
            case R.id.iocBtn:
                ToastUtil.showShort(this,"Button被点击",1);
                break;
            case R.id.iocIv:
                ToastUtil.showShort(this,"ImageView被点击",2);
                break;
            default:
                break;
        }
    }

    @BindOnClick(R.id.iocTv)
    @CheckNet //没网就不执行
    private void iocBtnClick(View view){
        ToastUtil.showShort(this,iocTv.getText().toString(),3);
    }
}

Fragment和自定义View里面也是类似的用法;