ViewCompat的作用
来源:互联网 发布:装修论坛 淘宝 编辑:程序博客网 时间:2024/05/01 04:45
ViewCompat类主要是用来提供兼容性的, 比如我最近看的比较的多的canScrollVertically方法, 在ViewCompat里面针对几个版本有不同的实现, 原理上还是根据版本判断, 有时甚至还要判断传入参数的类型. 但是要注意的是, ViewCompat仅仅让你调用不崩溃, 并不保证你调用的结果在不同版本的机器上一致.
关于如何优雅的组织代码, ViewCompat类的结构非常适合我们参考.
ViewCompat里面定义了一个接口, 这个接口列出了所有它支持的方法
interface ViewCompatImpl { public boolean canScrollHorizontally(View v, int direction); public boolean canScrollVertically(View v, int direction); public int getOverScrollMode(View v); public void setOverScrollMode(View v, int mode); ......}
ViewCompat类并非是在方法层面进行版本判断然后调用不同的方法, 而是在类的层面上做的, 也就是说在调用方法时并没有判断版本的调用, 因为一台手机的版本在开机到关机期间是不可能发生变化的, 所以只需要判断一次, 而这次判断放在了类的静态初始化块里.
static final ViewCompatImpl IMPL; static { final int version = android.os.Build.VERSION.SDK_INT; if (version >= 21) { IMPL = new LollipopViewCompatImpl(); } else if (version >= 19) { IMPL = new KitKatViewCompatImpl(); } else if (version >= 17) { IMPL = new JbMr1ViewCompatImpl(); } else if (version >= 16) { IMPL = new JBViewCompatImpl(); } else if (version >= 14) { IMPL = new ICSViewCompatImpl(); } else if (version >= 11) { IMPL = new HCViewCompatImpl(); } else if (version >= 9) { IMPL = new GBViewCompatImpl(); } else if (version >= 7) { IMPL = new EclairMr1ViewCompatImpl(); } else { IMPL = new BaseViewCompatImpl(); } }
这样我们就得到了针对各个版本的不同实现.
但是有些方法的实现在跨越几个版本的时候是不变的, 有些方法又有可能每次都变, 如何实现高效的代码复用呢? 那就是继承+重写.
比如BaseViewCompatImpl这个类是基类, 实现ViewCompatImpl接口, 把所有的方法都实现一次
static class BaseViewCompatImpl implements ViewCompatImpl { ...... public boolean canScrollHorizontally(View v, int direction) { return (v instanceof ScrollingView) && canScrollingViewScrollHorizontally((ScrollingView) v, direction); } public boolean canScrollVertically(View v, int direction) { return (v instanceof ScrollingView) && canScrollingViewScrollVertically((ScrollingView) v, direction); } ...... @Override public boolean isOpaque(View view) { final Drawable bg = view.getBackground(); if (bg != null) { return bg.getOpacity() == PixelFormat.OPAQUE; } return false; } ...... }
但是这些实现基本上都是空的, 或者无效的, 或者是一些workaround, 这也很正常, 因为确实不可能让每个方法都做到兼容, 只能尽量让他的版本支持多一点, 兼容性方法本来就有很多问题. 以上面这三个方法为例, 前两个方法都是api 14出现的方法, 在14以下基本上等于是直接返回了false(这里低版本是仅对ScollingView提供了支持, ScollingView有三个基类, 其中一个是RecyclerView), google显然没有想到什么好的方法在低版本提供对这个方法的支持, 所以干脆就在api小于14时一直使用这个实现, 而isOpaque则是类似workaround的方法, 在api 7时, isOpaque被正式添加到View类中, 所以在api 7我们可以直接调View的isOpaque, 那么应该怎么写代码呢? 应当新建一个类, 继承BaseViewCompatImpl, 重写isOpaque方法, 也就是下面这样:
static class EclairMr1ViewCompatImpl extends BaseViewCompatImpl { @Override public boolean isOpaque(View view) { return ViewCompatEclairMr1.isOpaque(view); } ...... }
而其他没有更好兼容方案的方法我们都不管, 那么api 9如果某些方法又有了更好的实现, 或者可以直接调用系统的api了, 就再新建一个类GBViewCompatImpl, 这个类需要继承EclairMr1ViewCompatImpl.
同理, 我们在api 14对应的类ICSViewCompatImpl中自然就会看到canScrollHorizontally和canScrollVertically的新的实现, 而ICSViewCompatImpl必然继承自HCViewCompatImpl.
就这样慢慢的演化, 像串铜钱一样, 每一个新的类对应一个新的版本(版本之间不需要连续), 同时继承自前一个版本的类, 在实现类的继承树上越接近叶子, 这个实现类的能力就越强.
最后看一下我们在代码里面使用这个类时的调用代码, 比如我要调用canScrollVertically方法, 那么我的代码一定是ViewCompat. canScrollVertically(v, dy), 看看这个方法对应的代码
public static boolean canScrollHorizontally(View v, int direction) { return IMPL.canScrollHorizontally(v, direction);}
ViewCompat相当于是一个中介, 它自己其实什么都不懂, 但是它认识一个懂的人IMPL, 它将所有的调用都交给了IMPL, 而IMPL在ViewCompat这个类加载时就已经根据当前系统版本实例化了, 不需要再判断版本了.
关于具体的使用请查看 官方文档
作者:万宵
链接:https://www.zhihu.com/question/27775923/answer/65086423
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- ViewCompat的作用
- ViewCompat.animate的使用
- ViewCompat
- ViewCompat.animate的用法和点击萎缩动画效果
- ViewCompat:android官方实现兼容的一个帮助类
- android中属性动画的bug,以及ViewCompat
- ViewCompat.animate 动画实现方式
- 作用域::的作用
- 作用域的作用
- ::的作用
- !!的作用
- Spring的作用、Struts的作用、Hiberante的作用
- android:supoort.v4.view.ViewCompat.getDisplay(Landroid/view/View;)Landroid/view/Display;
- 电容的作用?电容器的作用?
- 电话交换机的作用,程控交换机的作用
- 电容的作用?电容器的作用?
- 网络地址的作用,子网掩码的作用
- enum的作用以及主要的作用
- redis结构分析——ziplist
- iOS常用小功能(获得屏幕图像、压缩图片、加边框、调整label的size)
- popupwindow在不同theme时候的bug
- 秒杀系统架构分析与实战
- JayRock:JSON and JSON_RPC for .Net
- ViewCompat的作用
- 使用Jenkins搭建持续集成服务
- BZOJ 3576: [Hnoi2014]江南乐
- 《统计学习方法》-KNN笔记和python源码
- Eclipse打包时出现export aborted because fatal lint errors
- Hibernate配置文件与映射文件详解
- windows server 2008防火墙阻止局域网不能访问解决方案
- NTFS和FAT
- cookie 和session 的区别详解