Android移动架构汇总​​​​​​​

文章目录

一、控件的声明二、ViewBinding的基本使用三、ViewBinding特点四、ViewBinding的封装五、源码

一、控件的声明

在Activity中绑定布局中的控件一般有三种实现方式:

第一种用最原生态的findViewById方法来绑定第二种方式可以使用ButterKnife开源框架实现,ButterKnife对组件化的支持却很不友好第三种方式是使用Kotlin的扩展插件来获取视图控件,使用局限性:无法跨模块操作,类型不安全:不同的资源文件可以存在相同的控件id,因此在View层存在引用id来源出错的问题。

Kotlin 1.4版本中废弃了扩展插件,Google推荐使用ViewBinding来替代废弃的扩展插件

二、ViewBinding的基本使用

build.gradle中添加如下配置:

android {

...

viewBinding {

enabled = true

}

...

}

配置完成后,系统会为该模块中的每个XML布局文件生成一个绑定类,这个绑定类的命名就是XML文件的名称转换为驼峰式,并在末尾添加“Binding”一词,直接可以通过view binding这一中间类获取到xml中定义的view组件了

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// setContentView(R.layout.activity_new_stock_bjs_records);

viewBinding = ActivityNewStockBjsRecordsBinding.inflate(getLayoutInflater());

viewBinding.navigationBar.setText("北交所新股申购")

}

需要注意的一点是,开发者需要在onDestroyView()方法中将绑定类实例赋值为null。Fragment的存在时间比其视图时间长,所以开发者需要在onDestroyView()方法中清除对绑定类实例的所有引用,否则可能存在内存泄漏的风险

注意 如果某个布局文件不需要的话,可以通过tools:viewBinding-Ignore=“true”属性来设置

三、ViewBinding特点

集成简单代码简洁,维护容易对象空值安全:由于视图绑定会对视图直接引用,因此不存在因视图id无效而引发空指针异常的风险。类型安全:每个绑定类中的字段均具有与它们在xml文件中引用的视图相匹配的类型,因此不存在强制转换可能导致的异常问题

四、ViewBinding的封装

ViewBinding组件的使用流程基本是固定的,主要分为三步:

调用生成的绑定类中的inflate()方法来获取绑定类的实例。通过调用绑定类的getRoot()方法获取对根视图。将根视图传递到setContentView()中,并与当前Activity绑定。 由于ViewBinding使用的流程是固定的,因此在基础业务的开发中,经常会定义一个BaseActivity处理所有Activity的相同业务逻辑,这时,就可以将这部分逻辑封装在BaseActivity中

/**

* 使用ViewBinding的基础类

*

* @param

*/

public abstract class ViewBindingBaseActivity extends ActivityBase {

protected T mViewBinding;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mViewBinding = getViewBinding();

setContentView(mViewBinding.getRoot());

}

/**

* @return 返回Activity对于xml生成的ViewBinding对象

*/

public abstract T getViewBinding();

}

五、源码

在项目模块的build.gradle中开启ViewBinding功能之后,若进行项目编译,就会扫描layout下所有的布局文件,并生成对应的绑定类(Project视图: app/build/generated/data_binding_base_class_source_out/debug/out/包名/databinding路径下)。这一点是由gradle插件实现的

public final class ActivityTestBinding implements ViewBinding {

@NonNull

private final LinearLayout rootView;

@NonNull

public final ImageView imShezhi;

@NonNull

public final HomeRefresh reRefresh;

@NonNull

public final RecyclerView rv;

@NonNull

public final TextView tvName;

private ActivityTestBinding(@NonNull LinearLayout rootView, @NonNull ImageView imShezhi,

@NonNull HomeRefresh reRefresh, @NonNull RecyclerView rv, @NonNull TextView tvName) {

this.rootView = rootView;

this.imShezhi = imShezhi;

this.reRefresh = reRefresh;

this.rv = rv;

this.tvName = tvName;

}

@Override

@NonNull

public LinearLayout getRoot() {

return rootView;

}

@NonNull

public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater) {

return inflate(inflater, null, false);

}

@NonNull

public static ActivityTestBinding inflate(@NonNull LayoutInflater inflater,

@Nullable ViewGroup parent, boolean attachToParent) {

View root = inflater.inflate(R.layout.activity_test, parent, false);

if (attachToParent) {

parent.addView(root);

}

return bind(root);

}

@NonNull

public static ActivityTestBinding bind(@NonNull View rootView) {

// The body of this method is generated in a way you would not otherwise write.

// This is done to optimize the compiled bytecode for size and performance.

String missingId;

missingId: {

ImageView imShezhi = rootView.findViewById(R.id.im_shezhi);

if (imShezhi == null) {

missingId = "imShezhi";

break missingId;

}

HomeRefresh reRefresh = rootView.findViewById(R.id.re_refresh);

if (reRefresh == null) {

missingId = "reRefresh";

break missingId;

}

RecyclerView rv = rootView.findViewById(R.id.rv);

if (rv == null) {

missingId = "rv";

break missingId;

}

TextView tvName = rootView.findViewById(R.id.tv_name);

if (tvName == null) {

missingId = "tvName";

break missingId;

}

return new ActivityTestBinding((LinearLayout) rootView, imShezhi, reRefresh, rv, tvName);

}

throw new NullPointerException("Missing required view with ID: ".concat(missingId));

}

}

从生成的ActivityTestBinding文件中可以轻松地看出,在调用了inflate之后会调用bind方法,而bind方法依然是通过findViewById绑定

推荐阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: