Android:注解型框架原理浅析:在 DataBinding 框架出来之前,Android 有很多很多注解型框架,但是随着 DataBinding 的强势崛起,大多注解型框架都走投无路了。但是为了更好的了解技术,还是写了一个小小小的注解模型
作为一名初学者,已经厌烦了 findViewById 了,有没有更简单的办法去获取 xml 文件中的控件实例呢?使用注解就可以了。
注解:我们可以把它理解为是一种标记。通过反射机制 + 标记就能实现注解型框架了。
activity_main.xml
代码着实太简单了,就是定义了 id 分别为 username 和 password 的两个 TextView 控件。
我的目标就是:自动获取控件,并且为 id 为 a 的控件增加 onClickListener 监听,id 为 b 的控件增加 onLongClickListener 监听。
我们先定义注解吧
- @Target({
- ElementType.FIELD,
- ElementType.TYPE,
- ElementType.METHOD
- })@Retention(RetentionPolicy.RUNTIME) public@interface ViewAnnotation {
- int viewId()
- default 0;
- int layoutId()
- default 0;
- int onClick()
- default 0;
- int onLongClick()
- default 0;
- }
这里定义了四个方法,其实要使用的注解。因为写了 default,所以可以不同时使用者四个注解,viewId 是用来获取控件的,layoutId 是为 activity 设置布局的,onClick 是为了设置点击事件监听的,onLongClick 是为了设置长按事件监听的。
那我们开始在 activity 中使用这四个注解
- @ViewAnnotation(layoutId = R.layout.activity_main) public class MainActivity extends Activity {@ViewAnnotation(viewId = R.id.username) private TextView username;@ViewAnnotation(viewId = R.id.password) private TextView password;@ViewAnnotation(onClick = R.id.username) public void clickUsername(View view) {
- Toast.makeText(this, "onClickListener", Toast.LENGTH_LONG).show();
- }@ViewAnnotation(onLongClick = R.id.password) public void onLongClick(View view) {
- Toast.makeText(this, "onLongClickListener", Toast.LENGTH_LONG).show();
- }@Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ViewUtils.injectActivity(this);
- username.setText("Aiden");
- password.setText("123456");
- }
- }
可以看出,代码变得非常简单。在 onCreate() 函数中,写了 ViewUtils.injectActivity(this)。这是我自定义的 ViewUtils 类,然后不同 findViewById 了,因为我们用注解获取了那个实例了。
- public class ViewUtils { // 注入activity public static void injectActivity(Activity activity) { Class activityClass = activity.getClass(); injectContentView(activity, activityClass); injectView(activity, activityClass); injectListener(activity, activityClass); } // 设置contentView的 private static void injectContentView(Activity activity, Class activityClass) { if (activityClass.isAnnotationPresent(ViewAnnotation.class)) { ViewAnnotation inject = activityClass.getAnnotation(ViewAnnotation.class); int layoutId = inject.layoutId(); if (layoutId > 0) { activity.setContentView(layoutId); } } } // 获取控件的 private static void injectView(Activity activity, Class activityClass) { Field[] fields = activityClass.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(ViewAnnotation.class)) { field.setAccessible(true); ViewAnnotation inject = field.getAnnotation(ViewAnnotation.class); int id = inject.viewId(); if (id > 0) { try { field.set(activity, activity.findViewById(id)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } // 分别实现了点击事件和长按事件的监听 private static void injectListener(final Activity activity, Class activityClass) { Method[] methods = activityClass.getDeclaredMethods(); for (final Method method : methods) { if (method.isAnnotationPresent(ViewAnnotation.class)) { ViewAnnotation ViewAnnotation = method.getAnnotation(ViewAnnotation.class); int onClick = ViewAnnotation.onClick(); if (onClick > 0) { activity.findViewById(onClick).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { try { // 回调activity中的方法 method.invoke(activity, v); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } } ); } int onLongClick = ViewAnnotation.onLongClick(); if (onLongClick > 0) { activity.findViewById(onLongClick).setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { try { // 回调activity中的方法 method.invoke(activity, v); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return false; } }); } } } }}
至此,一个简单的注解型框架就形成了。当然了还有更多更多的细节需要处理的。比如说支持 Fragment、反射控件的更多方法(如 setAdapter() )等等。
作为小白,只知道这么多了
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: