手写IOC注解,解决findViewById和点击事件
来源:互联网 发布:淘宝网资产处置平台 编辑:程序博客网 时间:2024/06/16 20:08
在项目开发中findViewById以及控件的点击事件的场景是最多的,大量的findViewById并强转会浪费不少的开发时间,那么是否能解决掉这个问题呢?答案肯定是能解决;像xutils、butterKnidnife等主流第三方框架就很好的解决了这些问题,那么这些第三方的已经帮助开发者解决掉这些问题了,是否还要自己学着去写一套手写的IOC注解呢,肯定是需要的,在学习写的过程中能更好的理解这些第三方的实现原理,同时也能也符合项目的需要。下面这个是在学习过程中写的一个IOC注解:
涉及知识点:
1、注解
2、反射
3、动态代理(点击事件注入的时候会涉及到)
实现:
1、activity布局注入,不需要调用setContentView
2、activity、fragment等 findViewById、setOnClickListener、setOnLongClickListener等事件注入,点击和长按事件可轻松切换
代码实现:
ContentView 是用来activity布局注入:
/** * Created by Administrator on 2017/12/13. * activity 布局注入 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface ContentView { int value();}
activity布局注入逻辑:
/** * Activity加载布局 * * @param context */private static void injectLayout(Object context) { int layoutId = 0; Class<?> clazz = context.getClass(); //拿到activity类上面的注解 ContentView contentView = clazz.getAnnotation(ContentView.class); if (contentView != null) { layoutId = contentView.value(); try { Method method = clazz.getMethod("setContentView", int.class); method.setAccessible(true); try { //反射执行 method.invoke(context, layoutId); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } }}
ViewInject是findViewById注入:
/** * Created by Administrator on 2017/12/13. * findViewById注入 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface ViewInject { int value();}
findViewById注入逻辑:
/** * Activity加载view * * @param context */private static void injectView(ViewFinder finder, Object context) { Class<?> clazz = context.getClass(); //获取activity类中所有的成员变量 Field[] fields = clazz.getDeclaredFields(); //遍历 for (Field field : fields) { field.setAccessible(true); //得到成员变量的注解 ViewInject viewInject = field.getAnnotation(ViewInject.class); if (viewInject != null) { //获取对应的id int valueId = viewInject.value(); //反射获取控件 View viewById = finder.findViewById(valueId); if (viewById == null) { continue; } //反射调用方法 try { field.set(context, viewById); } catch (IllegalAccessException e) { e.printStackTrace(); } } }}
下面这些是点击事件、长按事件、条目点击事件等事件注入:
/** * Created by Administrator on 2017/12/15. * 对所有的点击事件扩展 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface EventBase { /** * 设置监听的方法 * @return */ String listenerSetter(); /** * 事件类型 * @return */ Class<?> listenerType(); /** * 回调方法 * 事件被触发后,执行回调方法名称 * @return */ String callBackMethod();}
/** * Created by Administrator on 2017/12/15. * 点击事件 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class, callBackMethod = "onClick")public @interface OnClick { /** * 点击事件控件数组 * @return */ int [] value()default -1;;}
/** * Created by Administrator on 2017/12/15. * 长按事件 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@EventBase(listenerSetter = "setOnLongClickListener", listenerType = View.OnLongClickListener.class, callBackMethod = "onLongClick")public @interface OnLongClick { int [] value() default -1;}
/** * Created by Administrator on 2017/12/15. * 条目点击事件 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@EventBase(listenerSetter = "setOnItemClickListener", listenerType = AdapterView.OnItemClickListener.class, callBackMethod = "onItemClick")public @interface OnItemClick { int [] value();}
在注入事件时涉及到动态代理的使用;
/** * Created by Administrator on 2017/12/15. * 动态代理 */public class ListenerInvocationHandler implements InvocationHandler{ //代理的真实对象 private Object context; private Map<String,Method> methodMap; public ListenerInvocationHandler(Object context, Map<String, Method> methodMap) { this.context = context; this.methodMap = methodMap; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); //决定是否需要进行代理 Method metf = methodMap.get(name); if(metf!=null){ return metf.invoke(context,args); }else{ return metf.invoke(proxy,args); } }}
事件注入逻辑:
/** * 事件注入 * * @param context */private static void injectEvents(ViewFinder finder, Object context) { Class<?> clazz = context.getClass(); //获取activity里面所有的方法 Method[] methods = clazz.getDeclaredMethods(); //循环遍历 for (Method method : methods) { //获取方法上面所有的注解 Annotation[] annotations = method.getAnnotations(); //循环遍历所有的注解 for (Annotation annotation : annotations) { //获取注解类型 Class<?> anntionType = annotation.annotationType(); //获取注解上面的注解 EventBase eventBase = anntionType.getAnnotation(EventBase.class); if (eventBase == null) { continue; } //开始获取事件三要素 通过反射注入进去 String listenerSetter = eventBase.listenerSetter(); Class<?> listenerType = eventBase.listenerType(); String callMethod = eventBase.callBackMethod(); //方法名与方法method进行对应关系 Map<String, Method> methodMap = new HashMap<>(); methodMap.put(callMethod, method); try { Method valueMethod = anntionType.getDeclaredMethod("value"); int[] viewIds = (int[]) valueMethod.invoke(annotation); //遍历获取到的id for (int viewId : viewIds) { //通过反射获取相应的view控件 View view = finder.findViewById(viewId); if (view == null) { continue; } Method setListener = view.getClass().getMethod(listenerSetter, listenerType); ListenerInvocationHandler handle = new ListenerInvocationHandler(context, methodMap); Object proxy = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, handle); setListener.invoke(view, proxy); } } catch (Exception e) { e.printStackTrace(); } } }}
activity中使用:
@ContentView(R.layout.activity_main)public class MainActivity extends AppCompatActivity { @ViewInject(R.id.tv_ioc) private TextView tvIOC; @ViewInject(R.id.tv_ioc1) private TextView tvIOC1; @ViewInject(R.id.tv_ioc2) private TextView tvIoc2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); InjectUtils.inject(this); tvIOC.setText("IOC注解 单击事件"); tvIOC1.setText("IOC注解 长按事件"); tvIoc2.setText("fragment IOC注解"); } @OnClick(R.id.tv_ioc) public void click(View view){ Toast.makeText(this,tvIOC.getText().toString(),Toast.LENGTH_LONG).show(); } @OnLongClick(R.id.tv_ioc1) public boolean longClick(View view){ Toast.makeText(this,tvIOC1.getText().toString(),Toast.LENGTH_LONG).show(); return true; } @OnClick(R.id.tv_ioc2) public void toFragment(View view){ startActivity(new Intent(this,SecondActivity.class)); }}
fragment中使用:
public class IOCFragment extends Fragment{ @ViewInject(R.id.tv_ioc) private TextView tvIOC; @ViewInject(R.id.tv_ioc1) private TextView tvIOC1; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_ioc, container, false); InjectUtils.inject(view,this); tvIOC.setText("IOC注解 fragment单击事件"); tvIOC1.setText("IOC注解 fragment长按事件"); return view; } @OnClick(R.id.tv_ioc) public void click(View view){ Toast.makeText(getActivity(),tvIOC.getText().toString(),Toast.LENGTH_LONG).show(); } @OnLongClick(R.id.tv_ioc1) public boolean longClick(View view){ Toast.makeText(getActivity(),tvIOC1.getText().toString(),Toast.LENGTH_LONG).show(); return true; }}
效果如下:
源码地址:
https://pan.baidu.com/s/1pL5gK4b
阅读全文
0 0
- 手写IOC注解,解决findViewById和点击事件
- 打造自己的IOC注解框架------findViewById
- 手写ButterKnife视图注入,解决findViewById
- Volley, HttpUtils,省略findViewById()和点击事件的.setOnClickListener(this);,DbUtils
- Volley, HttpUtils,省略findViewById()和点击事件的.setOnClickListener(this);,DbUtils
- Android 通过Annotation(注解方式)实现IOC,设置点击事件,初始化View
- android通过注解实现findViewById 和 setOnClickListener
- listview和checkbox点击事件冲突解决
- 很多点击事件,通过方法减少使用findViewbyid
- 使用注解提供view引用和点击事件
- 一种解决滑动事件和点击事件冲突的方法
- Android中通过注解代替findViewById方法 Android 中的 IOC 框架 【ViewInject】
- Android注解框架IOC(设置事件)
- Android中的IOC框架,完全注解方式就可以进行UI绑定和事件绑定
- Afinal的IOC原理-通过注解方法是绑定UI和事件源码分析
- 自己动手写一个简单的IOC框架,使用注解绑定资源和事件
- Android中注解和反射的结合findViewById
- findviewbyid和注解方式的自动生成工具
- react函数绑定this的方式。
- Linux POSIX 定时器 (timer_create)
- Bootstrap(四十二)
- Docker容器技术与传统的虚拟机技术的特性对比
- 计算任何一天是星期几的几种算法
- 手写IOC注解,解决findViewById和点击事件
- Android Handler机制
- Bootstrap(四十三)
- Android 自定义Toast
- 【软件工具】服务器硬件资源监控
- 装饰者模式
- pgsql 10.1 分区表之 range 分区
- Complex analysis review 2(Cauchy Integral Theory)
- Oracle数据类型对应Java类型