0

I'm using TextInputLayout in my application and when I add a TextWatcher to it's TextInputEditText that sets an error on the TextInputLayout, my app crashes when I trigger a configuration change.

editText.addTextChangedListener(object : TextWatcher {
    override fun afterTextChanged(text: Editable) {
        // no-op
    }
    override fun beforeTextChanged(text: CharSequence, start: Int, count: Int, after: Int) {
        // no-op
    }
    override fun onTextChanged(text: CharSequence, start: Int, before: Int, count: Int) {
        textInputLayout.error = if (text.isBlank()) {
            getString(R.string.error_text)
        } else {
            null
        }
    }
})

The stacktrace is

java.lang.NullPointerException: Attempt to read from field 'int android.view.View.mViewFlags' on a null object reference at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3863) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3864) at com.google.android.material.textfield.TextInputLayout.dispatchRestoreInstanceState(TextInputLayout.java:2053) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3864) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3864) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3864) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3864) at android.view.View.restoreHierarchyState(View.java:19808) at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:539) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:907) at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303) at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2656) at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2610) at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246) at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:542) at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1425) at android.app.Activity.performStart(Activity.java:7825) at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3294) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

tylerbwong
  • 15
  • 6

1 Answers1

0

It seems like you might need to override onViewStateRestored and remove/add your TextWatcher from there.

You should also save your TextWatcher somewhere that can survive a configuration change such as an Android ViewModel.

Here's a quick example:

// Inside of onViewStateRestored

if (viewModel.textWatcher != null) {
    editText.removeTextChangedListener(viewModel.textWatcher)
    viewModel.textWatcher = null
}

// Create and add TextWatcher back
tylerbwong
  • 15
  • 6
brittany
  • 16
  • 3