首页 > 解决方案 > 更改 customView 的层次结构时数据绑定中的 NPE 崩溃

问题描述

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout

class MyCustomView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null)  : FrameLayout(
    context,
    attributeSet
) {
    val binding = MylayoutBinding.inflate(
        LayoutInflater.from(context),
        this,
        true
    )
}

// mylayout.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <merge>
        <FrameLayout
            android:id="@+id/myChildContainer"
            android:layout_width="100dp"
            android:layout_height="100dp"/>
    </merge>
</layout>

我在下面的表格中使用我的自定义视图。

// myactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent">
        <MyCustomView
            android:id="@+id/myView"
            android:layout_width="300dp"
            android:layout_height="300dp">
            <Button
                android:id="@+id/myButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </MyCustomView>
    </FrameLayout>
</layout>

在上面的示例中,我希望 myButton 作为 myChildContainer 的子项进入 MyCustomView。

我遵循了android 中的示例:如何将 xml 布局中的子项添加到自定义视图中,并修改了 MyCustomView,如下所示。

class MyCustomView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null)  : FrameLayout(
    context,
    attributeSet
) {
    val binding = MylayoutBinding.inflate(
        LayoutInflater.from(context),
        this,
        true
    )

    override fun onFinishInflate() {
        super.onFinishInflate()
        while (childCount > 1) {
            val child = getChildAt(1)
            val param = child.layoutParams
            removeView(child)
            binding.myChildContainer.addView(child, param)
        }
    }
}

如果我不应用数据绑定,这段代码很好。

问题是当我应用数据绑定时应用程序崩溃了。

internal class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<MyactivityBinding>(this, R.layout.myactivity)
        binding.myButton.text = "Test Text" <-- crash
    }
}
Caused by: java.lang.NullPointerException: binding.myButton must not be null

当我将代码的remove view和addview的执行点从onFinishInflate更改为onAttachedToWindow时,一般不会出现错误,但是我已经确认它会间歇性地重复出现,所以我认为这不是一个解决方案。

有什么方法可以在保留 DataBinding 的同时将子视图添加到 CustomView?

我实际上使用了多个这样的视图,所以我不想在 setContentView 之后调用诸如 myView.sortView() 之类的单个函数。

标签: androidandroid-custom-viewandroid-databinding

解决方案


推荐阅读