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;
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 extends Activity> 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 extends Activity> 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;