Skip to content
Nate Ebel edited this page Jul 20, 2022 · 8 revisions

🖥 Lab 8: Validating Inputs and Restoring State

Let's add state restoration and input validation to our app.

 

📝 Objectives

  1. In CreateNoteFragment, write a function named areInputsEntered(): Boolean

    1. This function should return true if both titleEditText.text and noteEditText.text are not blank
    2. We will use this function to provide input validation for our Note creation workflow
  2. Hide the Save button until all three fields have input

    1. To do this, add android:visibility="gone" to your FloatingActionButton in fragment_create_note.xml
    2. We do this so a user cannot save a Note until the inputs are valid
  3. Respond to changes in the title text

    1. Add a TextChangeListener to titleEditText by creating an instance of TextWatcherAdapter (see notes)
    2. This listener should clear any errors on the titleInputContainer, so a change in the input moves the container back into a non-error state for the user
    3. This listener should update the visibility of the save button based on whether or not the inputs are vaild
  4. Respond to changes in the note text

    1. Add a TextChangeListener to noteEditText by creating an instance of TextWatcherAdapter (see notes).
    2. This listener should clear any errors on the noteInputContainer, so a change in the input moves the container back into a non-error state for the user
    3. This listener should update the visibility of the save button based on whether or not the inputs are vaild
  5. Display feedback to the user when save is clicked

    1. Add a click listener to the save button
    2. Show a Snackbar when the Button is clicked.
    3. When the Snackbar is dismissed, we should pop the current fragment off the stack using findNavController().popBackStack() (see hints)
  6. Deploy your app, and enter some text in an EditText. Rotate your device. What happens? Did you lose entered state? Try it again, but this time, use an EditText / TextInputLayout that does not included an android:id attribute. Does this change the state restoration behavior?

 

✨ Challenges

Exploring state restoration

  1. Within CreateNoteFragment, save a value to the Bundle in onSaveInstanceState().
  2. In onViewCreated(), check if that value is available in the Bundle and show it as a Toast.
  3. Use the techniques we discussed (breakpoints, logging) to explore which situations trigger state restoration.

 

🖥 Lab 8 Hints: Validating Inputs and Restoring State

💡 Helpful Resources

 

💡 How to create a TextChangeListener?

The addTextChangedListener method expects an instance of the TextWatcher interface, so we are free to implement that interface however we wish. Often, the easiest way is to create an unnamed, inline class as an object expression.

yourEditText.addTextChangedListener(object : TextWatcher {
  override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}

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

  override fun afterTextChanged(value: Editable?) {
    // respond to text changes here
  }
})

 

💡 How to respond to Snackbar dismissal

We can add a callback to a Snackbar. Within that callback, we can override onDismissed() to respond to the Snackbar being dismissed. This pattern is useful in cases where you want to trigger an action only after the user has had a change to view the feedback.

val snackbar = Snackbar.make(requireView(), "Saved the note!", Snackbar.LENGTH_SHORT)
snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
  override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
    super.onDismissed(transientBottomBar, event)
    // respond to dismissal
  }
})
snackbar.show()

 

💡 How to show an error with TextInputLayout?

TextInputLayout can animate into a styled error message by setting calling setError(msg). Check out the documentation for more on customizing the error message.

 

💡 How to validate that a String is not blank?

Kotlin has a number of helpful methods for checking the contents of a String

  • isBlank()
  • isEmpty()
  • isNotBlank()
  • isNullOrBlank()

 

💡 How to hide a View?

You can hide a View programmatically by setting view.visibility = View.GONE. You can show it again by setting view.visibility = View.VISIBLE.

Within xml, you can change a View's visibility using the android:visibility attribute with values gone, visible or invisible

Clone this wiki locally