65535 java_Databinding引起的 java方法大于 65535 的问题

# Databinding引起的 java方法大于 65535 的问题

## 前言

项目中开发使用的是 MVVM 开发模式,并且选择了 Databinding 作为 ViewModel 和 View之间通信的桥梁,再加上一定的封装,使用起来是挺方便的,但是也会遇到一些坑,比如我遇到的这个:

**Databinding 生成的 Java 文件中方法大于 65535 问题。**

如下图所示:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305150649.png)

## 缘由

这个问题是怎么来的呢?

其实触发条件挺小的,只有在特定的情况下才会遇到,要满足下面的条件:

1. 使用 Databinding

2. 项目要是中大型的项目(使用 Databinding 的xml文件多)

3. gradle 插件的版本要小于 3.2.0

## 模拟发生

新建项目,然后新建一个 Module:lib2,项目结构如图所示

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305151101.png)

然后分别在 app 和 lib2 的 build.gradle 中启用 Databinding

```shell

dataBinding{

enabled = true

}

```

设置 gradle 插件版本为 3.1.4. gradle 版本为:4.4

```shell

classpath 'com.android.tools.build:gradle:3.1.4'

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

```

然后创建一个 layout 文件:tag_activity_lib_main.xml

```xml

xmlns:tools="http://schemas.android.com/tools"

tools:ignore="MissingDefaultResource">

android:id="@+id/ll"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/tv"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="test" />

```

然后利用脚本把这个 xml 文件拷贝2000份,并分别改名字:

脚本:

```shell

#!/bin/bash

for b in {1..2000}

do

cp tag_activity_lib_main.xml ./tag_activity_lib_main$b.xml

done

```

然后把生成的2000份 xml 文件拷贝到项目的 layout 目录下(app 和 lib2 目录各1000各)。

这个时候应该就会见到这个错误了:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305150649.png)

我们看下这个报错的 DatabinderMapperImpl :

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305151909.png)

> ps:你的可能和我的不一样,xml 文件个数可能不同。

可以看到总共就那几个方法,却有2万多行代码,其中第一个 getDataBinder 方法很长,大概有15368 行,根据错误提示,可以初步断定就是就是这里的方法太大了,超过了 65535 的限制。

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305163944.png)

可以看到这个 getDataBinder 的作用就是根据传进来的view 的 tag 和 layoutId来返回 和 layoutId 对应的 ViewDataBinding 对象。

即:在 gradle 3.1.4 版本中,会把所有 module 的带有 ...标签的 xml 文件都对应生成一个 ViewDataBinding对象,然后在 DataBinderMapperImpl 中的 getDataBinder 中提供对应的映射关系。

并且会把这个 DataBinderMapperImpl 类放在 app-build-generated-source-apt-android.databinding目录下面。

可以看到:这个 DataBinderMapperImpl 类是在 apt 文件夹下面,也就是这个类是在编译器生成的,这就涉及到了 Android 中的APT 技术,当然这里的编译时生成代码的过程是 google 已经写好的,代码地址在:

[databinding仓库](https://android.googlesource.com/platform/frameworks/data-binding/+/refs/tags/gradle_3.1.2/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java) ,里面是具体的 APT 实现,有兴趣的可以去看看,其实是 google 在 Databinding 库中留下的坑,属于版本问题,好在后面的版本解决了这个问题。

## 解决

其实在 gradle 3.1.4 的下个版本 3.2.0中,google 已经解决这个问题。所以我们只用把 gradle 的版本升级到 3.2.0 以上就能避免这个问题的发生。

当然还有一个办法就是,后面你不再使用 Databinding 来开发,来避免这个问题,但是对于习惯使用 Databinding 的团队来说,这是很难受的,所以还是尽早升级下版本吧。

下面把 gradle 插件版本升级 3.2.0,并且同时要把 gradle 版本升级到 4.6.

执行编译:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305165129.png)

可见这里已经执行成功了。我们再来看下刚才 app - build 下面出错的 DataBinderMapperImpl 文件:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305165258.png)

看下 com.example.databindinganalysis 下面的 DataBinderMapperImpl:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305165411.png)

可以看到,在新版本的 DataBinderMapperImpl 的 getDataBinder 方法中,google 已经把获取 ViewDataBinding 的操作进行了拆分,使用 internalGetViewDataBindingXX 对所有的 layout 文件进行分组,每个组建立了 50 个映射关系,比如 internalGetViewDataBinding0 的代码如下:

![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200305165557.png)

装对 getDataBinder 的拆分很好的避免了上面遇到问题的发生。

此外,在gradle 3.1.4 版本中,app module 和 lib2 module 的 DataBinderMapperImpl 文件都是在 app module 下面的 build 文件夹下面生成的,但是在 gradle 3.2.0 版本中,会对每个 module 都生成一个 DataBinderMapperImpl 文件,这样产生 上面代码过长的问题的概率又小了许多,事实上,一个正常的项目不会再发生上面的编译错误了。

最后再贴一下 Databinding 仓库的地址:

https://android.googlesource.com/platform/frameworks/data-binding/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值