IOC框架(一)

1. IOC


Inversion of Control,控制反转,
目的是:帮我们注入setContentView布局文件、注入findViewById、注入onClick事件;

这篇文章只是记录 注入setContentView布局文件、注入findViewById

注入setContentView布局文件:在Activity类上添加注解,自动帮我们注入布局文件;
注入findViewById:在Activity中每个控件添加注解,自动帮我们findViewById;

下边通过
注入 setContentView布局文件,替代传统的 setContentView(R.layout.activity_zhujie);
注入 InjectView,替代传统的 findViewById;

2. 效果如下


点击111 - 弹出 111;
点击222 - 弹出 222;


图片.png

3. 代码如下


1>:定义两个注解:

第一:ContentView :用于类上声明哪个布局文件

// Target:表示作用在哪里 FIELD:成员变量 TYPE:类 CONSTRUCTOR:构造方法
@Target(ElementType.TYPE)
// Retention: 表示什么时候生效 RUNTIME:运行时 CLASS:编译时 SOURCE: 源码资源
@Retention(RetentionPolicy.RUNTIME)
// ContentView: 在类上边使用,用于标明该Activity需要使用的布局文件
public @interface ContentView {
    int value();
}

第二:ViewInject :用于成员变量,findViewById

// Target:表示作用在哪:FIELD:成员变量 TYPE:类 CONSTRUCTOR:构造方法
@Target(ElementType.FIELD)
// Retention:表示什么时间生效 RUNTIME:运行时 CLASS: 编译时 SOURCE:源码资源
@Retention(RetentionPolicy.RUNTIME)
// ViewInject: 在成员变量上使用,用于指定View的id
public @interface ViewInject {
    int value();
}
2>:ViewInjectUtils
/**
 * ================================================
 * Email: [email protected]
 * Created by Novate 2019/1/2 10:15
 * Version 1.0
 * Params:
 * Description:    反射注入setContentView、findViewById
 * ================================================
*/

public class ViewInjectUtils {

    private static final String METHOD_SET_CONTENTVIEW = "setContentView";
    private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";

    public static void inject(Activity activity){
        // setContentView
        injectContentView(activity);
        // findViewById
        injectViews(activity);
    }

    /**
     * 注入:setContentView
     */
    private static void injectContentView(Activity activity){
        // 传递activity对象,获取它的Class类型
        Class clazz = activity.getClass();
        // 判断这个类中是否写了ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        // 如果写了该注解
        if (contentView != null){
            // 读取该注解的value
            int contentViewLayoutId = contentView.value();
            try{
                // 得到 setContentView 这个方法,然后调用 invoke 即可
                Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW,
                        int.class);
                method.setAccessible(true);
                method.invoke(activity, contentViewLayoutId);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }



    /**
     * 注入:findViewById
     */
    private static void injectViews(Activity activity){
        // 传递activity对象,获取它的Class类型
        Class clazz = activity.getClass();
        // 获取该类中所有的字段(成员变量,不是方法) public、private、protected,不包括父类字段
        // getFields(): 获取该类中所有的public字段(成员变量,不是方法)
        // getConstructors()和getDeclaredConstructors():表示获取某个类的构造函数
        // getMethods()和getDeclaredMethods(),表示获取某个类的方法
        Field[] fields = clazz.getDeclaredFields();
        // 遍历所有成员变量
        for (Field field : fields){
            // 获取该变量的ViewInject注解
            ViewInject viewInjectAnnotation = field
                    .getAnnotation(ViewInject.class);
            // 如果该变量写了 ViewInject注解
            if (viewInjectAnnotation != null){
                // 获取value
                int viewId = viewInjectAnnotation.value();
                if (viewId != -1){
                    Log.e("TAG", viewId+"");
                    // 初始化View
                    try{
                        // 调用findViewById,调用反射执行
                        Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID,
                                int.class);
                        Object resView = method.invoke(activity, viewId);
                        field.setAccessible(true);
                        field.set(activity, resView);
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
3>:activity_zhujie.xml



    
4>:ZhuJieActivity
/**
 * ================================================
 * Email: [email protected]
 * Created by Novate 2019/1/2 13:48
 * Version 1.0
 * Params:
 * Description:    注入setContentView、findViewById
 * ================================================
*/

// 反射注入 setContentView主布局文件
@ContentView(value = R.layout.activity_zhujie)
public class ZhuJieActivity extends AppCompatActivity implements View.OnClickListener{

    // 反射注入 findViewById
    @ViewInject(R.id.id_btn)
    private Button mBtn1 ;
    @ViewInject(R.id.id_btn02)
    private Button mBtn2;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ViewInjectUtils.inject(this);

        mBtn1.setOnClickListener(this);
        mBtn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.id_btn:
                Toast.makeText(ZhuJieActivity.this , "111" , Toast.LENGTH_SHORT).show();
                 break;
            case R.id.id_btn02:
                Toast.makeText(ZhuJieActivity.this , "222" , Toast.LENGTH_SHORT).show();
                break;
        }
    }
}
以上就实现了用:

反射注入 setContentView主布局文件,实现了传统的 setContentView;
反射注入 ViewInject,实现了传统的 有多少个控件,就有多少个findViewById;

你可能感兴趣的:(IOC框架(一))