Android开发 |
您所在的位置:网站首页 › zippo盔甲机哪一年生产的 › Android开发 |
1. 前言
如何干掉模版代码是很多第三方框架的设计初衷,在Android开发中,findViewById()是必不可少的存在,这样的冗余代码在很久以前充斥在Android工程中,因此也出现了很多精简方案。在Android Studio3.6中加入了很多新特性——View Binding就是其中之一。目前已经在工程中使用并上线,未出现稳定性问题,因此做以下记录。在谈View Binding之前,我们先聊一下在此之前有哪些代表性方案做过这个事情,以及它们的优缺点分析。
1.1 Butter Knife/Kotter Knife
Butter Knife框架是17年前后很火的存在。但是在Kotlin中直接使用ButterKnife的注解方式的话,会出现空指针的异常并导致绑定失败。从而Kotter Knife应运而生,可以理解成是Butter Knife的Kotlin版本。用法如下: //Butter Knife @BindView(R.id.title) TextView title; ButterKnife.bind(this); // TODO Use fields... // Kotter Knife val submitButton: Button by bindView(R.id.submit_button) // TODO Use val...然而这种方案已经被作者标记为Deprecated,作者认为该框架为每个视图引用分配了一个对象,这种思路不应该被采用,以及使用这种思路的框架也应该被淘汰,并推荐使用ViewBinding的方式。 1.2 Data Binding依稀记得Data Binding是16年底的时候推出的,那时候真的很火,因为它是谷歌对于MVVM开发模式在Android上体现之一,其底层通过Annotation Processor实现的。用法如下,关键就是新增了data节点,以及在layout中的属性表达式@{}。 默认情况下,基于layout文件的名称会生成单词首字母大写并添加“Binding”后缀一个Binding类。此类包含layout属性以及在Views中的所有binding属性(例如user变量),并且能够为该属性赋值。因此在Java代码中: MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); User user = new User("firstName", "lastName"); binding.setUser(user);但是Data Binding的劣势也很明显: 它侵入了xml文件,因为只有布局文件的根标签必须是layout时, Data Binding才会生成对应的Binding Class。Annotation Processor不仅对构建速度有负面影响,也会产生部分性能问题。最最关键的,一些Data Binding相关的bug很难跟踪和解决,开发者在MVVM模式上的bug需要花费更多的时间,我觉得这也是MVVM没有在移动端发展起来的原因之一。 2. View Binding这就是今天的主角了,View Binding既不会像Butter Knife那样为View分配多余的对象,也不会像Data Binding那样使用Annotation Processor,它的实现既简单又强大。首先来看一下如何使用View Binding。 2.1 View Binding所需环境 首先需要将Android Studio升级到3.6版本及以上升级Gradle plugin版本到3.6.1并在app模块中手动开启view binding开关(View Binding以模块为粒度进行开启/关闭) buildscript { ... dependencies { classpath "com.android.tools.build:gradle:3.6.1" } } android { ... viewBinding { enabled = true } }这里升级gradle的时候遇到了一些小坑,即工程中使用的tinker版本过低,其使用了旧版gradle中的语法,因此会报错,将tinker版本升级到’1.9.14.6’后问题解决。 2.2 View Binding的使用activity_main.xml的布局如下: 这里直接include了一个子布局,inner_layout.xml的布局如下: 默认情况下,每一个布局xml文件都会生成一个对应的Binding类,名字的生成规则同Data Binding。在该例子中,会自动为我们生成一个ActivityMainBinding.java,以及include的标签对应的InnerLayoutBinding,这里include必须指定一个id。当然,如果不需要为该xml生成Binding类,可以在xml的根布局中配置tools:viewBindingIgnore=“true”。 在Java中的使用如下所示: public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); binding.firstButton.setText("Text Change"); binding.innerLayout.innerLayoutSecondButton.setText("Inner Layout Button Text Change"); } }用法也很简单,直接通过binding点名字的方式就可以获取到控件实例,消除了findViewById的模版代码。 这里可以看到,setContentView的入参写法都变了,因为可通过XXXBinding类的getRoot函数获取到布局的根View,再通过setContentView添加到Activity。 2.3 View Binding的一些注意点在2.2中我们演示了include的用法,只需要加一个id,我们就可以通过binding.innerLayout获取到该子布局。但是有个特殊情况需要处理,就是merge标签。 如果子布局inner_layout.xml中的布局如下,多了一个merge标签: 那么在activity_main.xml的布局的include标签中就一定不要设置id了(这里就不贴activity_main.xml的代码了),否则会找不到View报空指针异常。这个情况,我们可以先初始化主布局,再初始带merge的布局,那么就需要用到View Binding的另一个构造方法了,处理如下: public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); //使用 binding.firstButton.setText("Text Change"); //merge标签处理 InnerLayoutBinding subBinding = InnerLayoutBinding.bind(binding.getRoot()); subBinding.innerLayoutSecondButton.setText("Inner Layout Button Text Change"); } } 2.4 View Binding的原理解析从2.2和2.3中我们看到了Binding类的两种构造方法,其实它有三种使用方法,如下所示: inflate(@NonNull LayoutInflater inflater) inflate(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, boolean attachToParent) bind(@NonNull View rootView) 第一种和第二种直接调用inflate()方法,传入inflater即可得到Binding类的实例,它会在内部inflate对应的xml布局,并得到并持有该xml布局的根布局View实例,即例子中的binding.getRoot()。inflate()最后仍然会调用bind()。第三种方法就更简单粗暴了,直接使用bind()方法并传入View实例,这个View实例可以是你在外部自己生成的,即可为你生成一个Binding类的实例,再通过点view的方式,找到传入的根View下的子View实例。比如在我们的工程中,在Adapter中封装了ViewHolder加载xml的过程并将根布局view放在了ViewHolder的基类里,这种情况显然就只能使用bind(view)的方式了。这里以2.2中生成的Binding类为例,该类的路径如下所示:![]() |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |