一、 概述
IoC,就是控制反转(Inversion of Control),缩写为 IoC。
简单来说,就是不需要手动 new 对象,只需要在配置文件或者注解指定一下类名,让框架去解析配置文件或者注解,然后利用反射实例化我们配置的类。
本文目的是利用注解实现setContentView、findViewById、setOnClickListener的代码由框架自动生成。
1.工程结构
image.png2.体验代码
/**
* @description 测试的Activity
* @author: dzh
* @CreateDate: ${DATE} ${TIME}
*/
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.tvTest)
TextView tvTest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
Views.inject(this);
}
@OnClick(R.id.tvTest)
public void showText(View v) {
String text = tvTest.getText().toString();
Toast.makeText(this, "获取到tvTest上的文本是:" + text, Toast.LENGTH_SHORT).show();
}
}
二、具体实现步骤
1.创建绑定布局的注解
/**
* @Description: 绑定布局
* @Author: dzh
* @CreateDate: 2019-12-02 13:59
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int NONE = -1;
int value() default NONE;
}
2.创建控件注入的注解
/**
* @Description: 控件注入
* @Author: dzh
* @CreateDate: 2019-12-02 14:00
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int NONE = -1;
int value() default NONE;
}
3.创建绑定点击事件的注解
/**
* @Description: 点击事件
* @Author: dzh
* @CreateDate: 2019-12-02 14:00
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
int NONE = -1;
int value();
}
4.实现注解的解析类
/**
* @Description: 注解解析类
* @Author: dzh
* @CreateDate: 2019-12-02 14:03
*/
public class Views {
public static void inject(final Activity activity) {
injectContentView(activity);
injectViews(activity);
injectOnClickListener(activity);
}
/**
* 解析视图
*
* @param activity activity
*/
private static void injectContentView(Activity activity) {
Class<? extends Activity> activityClass = activity.getClass();
ContentView contentViewAnnotation = activityClass.getAnnotation(ContentView.class);
if (contentViewAnnotation == null) {
return;
}
int layoutResId = contentViewAnnotation.value();
if (layoutResId == ContentView.NONE) {
return;
}
activity.setContentView(layoutResId);
}
/**
* 解析控件
*
* @param activity activity
*/
private static void injectViews(Activity activity) {
Class<? extends Activity> activityClass = activity.getClass();
Field[] fields = activityClass.getDeclaredFields();
for (Field field : fields) {
ViewInject viewInjectAnnotation = field.getAnnotation(ViewInject.class);
if (viewInjectAnnotation == null) {
continue;
}
int viewResId = viewInjectAnnotation.value();
if (viewResId != ViewInject.NONE) {
try {
View view = activity.findViewById(viewResId);
field.setAccessible(true);
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
/**
* 解析点击事件
*
* @param activity activity
*/
private static void injectOnClickListener(final Activity activity) {
Class<? extends Activity> activityClass = activity.getClass();
Method[] methods = activityClass.getDeclaredMethods();
for (final Method method : methods) {
OnClick onClickAnnotation = method.getAnnotation(OnClick.class);
if (onClickAnnotation == null) {
continue;
}
int viewResId = onClickAnnotation.value();
if (viewResId == OnClick.NONE) {
continue;
}
try {
final View view = activity.findViewById(viewResId);
if (view != null) {
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(activity, view);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
三、总结
源码:https://github.com/stormdzh/AndroidIOC
通过反射实现,是运行时注解对性能有一定的影响!可以考虑是用apt实现。
网友评论