优雅FindViewById
findBiewById
findBiewById 是 Android 开发中在布局中查找 View 元素的 Api。
findBiewById 基本使用
1 | class DemoActivity extends AppCompatActivity { |
因为写起来很繁琐(而且还需要手动强转类型),所以逐渐出现了各种简化或者代替它的方式。
省略强转
从 Android Support Library 26.0.0 Beta 1 开始 findViewById 将不再需要强转了。
findViewById() 方法的所有实例现在会返回 <T extends View> T,而不是 View。
1 | class DemoActivity extends AppCompatActivity { |
findBiewById 原理
findBiewById 原理实质上是递归遍历查找匹配 Id 的 View。
Activity 中 findViewId 方法会调用获取 Window -> DecoreView -> View 的 findBiewById 方法。
最终会调用到 View 中的 findViewTraversal 方法。方法名看上去是遍历操作,在 View 类中找不到遍历逻辑;
实际上 ViewGroup 覆写了 View 的 findViewTraversal 方法,实现了递归遍历查找匹配 View 的方法。
1 | class View { |
ButterKnife
ButterKnife 是 jakewharton 大神开源作品,用于替代 findViewById ,避免繁琐的写法。
ButterKnife 基本使用
1 | class DemoActivity extends AppCompatActivity { |
ButterKnife 原理
注解编译时生成绑定类,代替我们完成 FindViewById 的操作。
PS:ButterKnife Github ReadMe 中说明已不推荐使用,推荐下文提到的 Android 官方提供的 ViewBinding
Data Binding Library
Data Binding 基本使用
布局需要使用 <layout> 标签包裹。
1 | class DemoActivity extends AppCompatActivity { |
Data Binding 原理
自动查找所有 View 并缓存到 binding 实例中以供访问。性能超过手写的 findViewById,因为它只遍历了一遍 XML 布局,而 findViewById 每次都会去遍历 XML 布局;include 布局中的 view 也能同样能访问,并且保留结构。
Kotlin Android Extensions
直接生成对应的 View 作为属性,不需要 findViewById,不需要定义变量,直接使用。使用时需要注意访问的 View 属于哪个 Layout,因为智能提示的候选项会提供所有布局中的 View 供你选择,然后帮你 import 对应包以便你访问这个 View;假如 import 的多个同一层级的 layout 中具有相同的 id,则这个 id 对应的 View 将无法访问。
Kotlin Android Extensions synthetic 基本使用
1 |
|
Kotlin Android Extensions synthetic 原理
Kotlin 会自动生成类似 findViewById() 的方法:findCachedViewById(),在这个方法里面创建一个 HashMap 缓存每次查找到的 View,避免每次调用 View 的属性或方法时都会重新调用 findCachedViewById() 进行查找。
PS:在 Kotlin 1.4.20-M2 中,JetBrain s废弃了 Kotlin Android Extensions 编译插件。推荐使用 ViewBinding。
(推荐使用)ViewBinding
ViewBinding 基本使用
Android Studio 3.6 Canary 11 及更高版本中可用。
1 | android { |
1 | class DemoActivity : AppCompatActivity() { { |
ViewBinding 原理
ViewBinding 优缺点
优点
Null 安全:由于视图绑定会创建对视图的直接引用,因此不存在因视图 ID 无效而引发 Null 指针异常的风险。此外,如果视图仅出现在布局的某些配置中,则绑定类中包含其引用的字段会使用 @Nullable 标记。
类型安全:每个绑定类中的字段均具有与它们在 XML 文件中引用的视图相匹配的类型。这意味着不存在发生类转换异常的风险。
更快的编译速度:视图绑定不需要处理注释,因此编译时间更短。
易于使用:视图绑定不需要特别标记的 XML 布局文件,因此在应用中采用速度更快。在模块中启用视图绑定后,它会自动应用于该模块的所有布局。
缺点与限制
- 布局和代码之间的不兼容性可能会导致编译版本在编译时(而非运行时)失败。
- 视图绑定不支持布局变量或布局表达式,因此不能用于直接在 XML 布局文件中声明动态界面内容。
- 视图绑定不支持双向数据绑定。
相关文章
使用视图绑定替代 findViewById
你好, View Binding! 再次再见, findViewById!
Kotlin 干掉了 findViewById,但用不好也会有性能问题
Migrating the deprecated Kotlin Android Extensions compiler plugin
【译】迁移被废弃的Kotlin Android Extensions插件