使用双向数据绑定的自定义视图

7
我有一个自定义视图,它扩展了LinearLayout并填充了一个包含几个视图的布局。
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <EditText
        android:id="@+id/voice_edittext"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:hint="Add answer here"
        />

    <ImageButton
        android:id="@+id/microphone_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_mic_black_24dp"
        />
    <ImageButton
        android:id="@+id/delete_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_cancel_black_24dp"
        android:visibility="gone"
        />
    </LinearLayout>

现在我想要使用这个视图时,双向绑定Edittext的文本值,像这样:

<com.sunilson.quizcreator.presentation.views.EditTextWithVoiceInput
                android:id="@+id/form_question"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_marginTop="10dp"
                app:editTextValue="@={viewModel.observableText}"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

为此,我创建了一些绑定适配器。
@BindingAdapter("editTextValueAttrChanged")
fun setListener(editTextWithVoiceInput: EditTextWithVoiceInput, listener: InverseBindingListener) {
    editTextWithVoiceInput.voice_edittext.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(p0: Editable?) {
            listener.onChange()
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    })
}

@BindingAdapter("editTextValue")
fun setTextValue(editTextWithVoiceInput: EditTextWithVoiceInput, value: String?) {
    if (value != editTextWithVoiceInput.voice_edittext.text.toString()) editTextWithVoiceInput.voice_edittext.setText(value)
}

@InverseBindingAdapter(attribute = "editTextValue")
fun getTextValue(editTextWithVoiceInput: EditTextWithVoiceInput): String? {
    return editTextWithVoiceInput.voice_edittext.text.toString()
}

这是视图的代码:

class EditTextWithVoiceInput(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {

    init {
        val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val view = inflater.inflate(R.layout.voice_edittext, this, true)

        view.microphone_button.setOnTouchListener { p0, p1 ->
            ...
        }
    }
}

现在的问题是,当包含视图的片段启动时,我会收到以下错误:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.sunilson.quizcreator, PID: 12627
              java.lang.NullPointerException: Attempt to invoke virtual method 'void com.sunilson.quizcreator.presentation.views.EditTextWithVoiceInput.setTag(java.lang.Object)' on a null object reference
                  at com.sunilson.quizcreator.databinding.FragmentAddQuestionBinding.<init>(FragmentAddQuestionBinding.java:112)
                  at android.databinding.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:15)
                  at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
                  at android.databinding.DataBindingUtil.inflate(DataBindingUtil.java:130)
                  at android.databinding.DataBindingUtil.inflate(DataBindingUtil.java:95)
                  at com.sunilson.quizcreator.presentation.SingleActivity.fragments.AddQuestionFragment.AddQuestionFragment.onCreateView(AddQuestionFragment.kt:34)
                  at android.support.v4.app.Fragment.performCreateView(Fragment.java:2425)
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
                  at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
                  at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
                  at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2623)
                  at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2410)
                  at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2365)
                  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2272)
                  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
                  at android.os.Handler.handleCallback(Handler.java:789)
                  at android.os.Handler.dispatchMessage(Handler.java:98)
                  at android.os.Looper.loop(Looper.java:180)
                  at android.app.ActivityThread.main(ActivityThread.java:6944)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:835)

我在这里缺少什么?


你缺少了堆栈跟踪。它会告诉你问题出现的位置。 - tynn
@tynn 抱歉,我已将其添加到帖子中。 - sunilson
1个回答

2

好的,我的问题是自定义视图没有正确实现构造函数。因为我在XML中填充这个视图,所以我需要传递Attributeset给父类构造函数的构造函数,但我没有这样做。没有这个,我的视图没有属性,不能通过ID等找到。

现在我有两个构造函数,取决于我是从XML还是代码膨胀:

constructor(context: Context, optional: Boolean) : super(context) {
        ...
    }

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        ...
    }

我已经在我的构造函数中使用了JvmOverloads,但仍然遇到了这个问题。:( 有什么想法吗?CustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) - programmer dreamer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接