当 minSdkVersion 为 >= 26 时,动态功能模块的生成绑定类上的 NullPointerException [英] NullPointerException on generated binding class for dynamic feature modules when minSdkVersion is >= 26

查看:27
本文介绍了当 minSdkVersion 为 >= 26 时,动态功能模块的生成绑定类上的 NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 MinSdkVersion 从 25 更新到 26,但在访问生成的绑定类的属性时收到 NullPointerExceptions.

I am trying to update my MinSdkVersion from 25 to 26, but I receive NullPointerExceptions when accessing properties of the generated binding classes.

以下代码段显示了哪一行代码导致了 NPE:

The following snippet shows which line of code causes a NPE:

class DynamicActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding: ActivityDynamicBinding = DataBindingUtil.setContentView(
            this, R.layout.activity_dynamic)

        // Access a random binding to do a random thing
        binding.observableFieldsActivityButton.setOnClickListener { // This is the line it will crash
            Log.i("Tag", "I did a random thing, it works")
        }
        binding.viewmodelActivityButton.setOnClickListener {
            Log.i("Tag", "I did another random thing, it works")
        }
    }
}

binding.observableFieldsActivityButton 为空.

这是 XML 文件:

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

                <Button
                    android:id="@+id/observable_fields_activity_button"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:text="@string/observable_fields_activity_text"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/observableactivity_activity_label"/>

<!-- The rest -->

这是堆栈跟踪:

FATAL EXCEPTION: main
    Process: com.example.android.databinding.twowaysample, PID: 27268
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.databinding.twowaysample/com.example.dynamicfeature.DynamicActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at com.example.dynamicfeature.DynamicActivity.onCreate(DynamicActivity.kt:17)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)

这似乎只有在动态功能中使用数据绑定时才会发生(这个 DynamicActivity 是我的动态功能模块中的活动)

This only seems to happen when using databinding in a dynamic feature (this DynamicActivity is the activity in my dynamic feature module)

我已经在内部调试了数据绑定库中发生的事情,我也找到了这些问题的原因.

I have already debugged what happens in the databinding library internally, and I have also found the cause of these issues.

在第 1020 行的 ViewDataBinding.java 类中,它检查生成的视图 ID 是否为 >0 (http://androidxref.com/9.0.0_r3/xref/frameworks/data-binding/extensions/library/src/main/java/android/databinding/ViewDataBinding.java#1020)

In the class ViewDataBinding.java on line 1020 it checks if the generated view id is > 0 (http://androidxref.com/9.0.0_r3/xref/frameworks/data-binding/extensions/library/src/main/java/android/databinding/ViewDataBinding.java#1020)

当将 minSdkVersion 升级到 26 或更高版本时,动态功能模块的生成视图 ID 为负数,而将 minSdkVersion 设置为 25 或更低时,这些视图 ID 为正数.

When upgrading the minSdkVersion to 26 or above, the generated view ids for dynamic feature modules are negative, whereas these are positive when setting minSdkVersion to 25 or lower.

这会导致 DataBinding 跳过这些视图,导致它们稍后为空.

This causes the DataBinding to skip these views, causing them to be null later on.

有人解决这个问题吗?我正在考虑强制构建过程只生成带有正整数的 ID.

Does someone have a solution to this? I am thinking of something to force the build process to only generate ids with positive integers.

看来这个错误已经在谷歌的问题跟踪器上创建了:https://issuetracker.google.com/issues/123304430

It appears this bug is already created on the issue tracker of google: https://issuetracker.google.com/issues/123304430

推荐答案

如问题中所述,这是一个已知错误.我发现的解决方法是:

As mentioned in the question this is a known bug. Workarounds I have found are:

  1. 在根上使用 findViewById 而不是直接访问字段.
  1. using findViewById on the root instead of the direct access to the field.

    val view = binding.root.findViewById<View>(R.id.my_view)
    // val view = binding.MyView // Original (now broken) code

  1. 在 xml 中绑定一个虚拟值.不确定这是一个好主意还是一个糟糕的主意,但在我看来,只有当您实际上没有将任何数据绑定到您的 xml 中的视图而是在您的代码中访问它时,才会出现该错误.您可以通过绑定一个虚拟值来欺骗数据绑定以不同的方式创建实现,例如通过将其添加到视图中:

    android:tag="@{null}"

#2 依赖于数据绑定工具实现,将来可能会中断.但是,事后清理也更容易(搜索/替换).

#2 relies on the databinding tooling implementation and might break in future. However, it is also easier to clean up afterwards (search / replace).

这篇关于当 minSdkVersion 为 &gt;= 26 时,动态功能模块的生成绑定类上的 NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆