Search code examples
androidkotlindata-bindingandroid-livedatamutablelivedata

Keep updating the same activity with different data on button click


I have an android application that asks users a few questions, kind of a survey. Each question has an YES and a NO Button. So when the user presses either YES or NO button, a new Button to go to the next question becomes visible over the YES and NO buttons. When the user clicks on the next question button it changes the textview for the question to the next question text as well as the imageView for that question changes.

I am making use of DataBinding along with LiveData.

I have created a list of images used and another list for the questions as follows in my ViewModel class.:

//list of images : Question 4 does not have an image
imgs= listOf(
        R.drawable.imgQ1, // 1
        R.drawable.imgQ2,// 2
        R.drawable.imgQ3)//3

//list of questions
qs= listOf(
   "What is .....?",//1
   "Who is ....?",//2
   "How to .....?",//3
   "Why is .....?")//4

I created a ViewState to handle when to show which button and UI:

sealed class MyUIState{

    data class UIState(
        val policyText: Boolean, // determines if the policy textview should be visible or not
        val nextQuestionButton: Boolean,// determines if the next question button should be visible or not
        val nextQuestionNewImage: Int = R.drawable.imgQ1,//what image is used for the next question
        val nextQuestion: String //what is the next question from the list
    ) : MyUIState()
}

I also have a BindingAdapter class which handles the visibility and text changes and image changes (basically this - I have added these function to my layout file with data binding):

@BindingAdapter("btnNextQ")
fun Button.btnNextQ(myState: MyUIState?){

    visibility = if (myState is MyUIState.UIState) {
        if (state.nextQuestionButton)
            View.VISIBLE
        else
            View.GONE
    } else
        visibility
}

@BindingAdapter("newImage")
fun ImageView.newImage(myState: MyUIState?){

    if(myStateis MyUIState.UIState){
        setImageResource(state.nextQuestionNewImage)
    }
}

And then in my ViewModel class I have a function for the click event on either the YES or NO Button where I call the UIState like this:

//I have this declared at the top of my class (global)
private val myViewState = MutableLiveData<MyUIState>()

//this the button click for yes:
fun YesClick(){

    myViewState.postValue(MyUIState.UIState(
        policyText= true,
        nextQuestionButton = true,
        nextQuestion =  qs[0])) //still keep the text for question1

}

Now, I want the image and question to change after the user clicked the next question button. So basically what happens is that after clicking next question, the next question buttons goes invisible as well as the other components keeping the YES and NO buttons and the updated question and image. This is my code for the click event on the next question button:

fun nextQuestion(){

        myViewState .postValue(MyUIState.UIState(
            nextQuestionNewImage = imgs[1],
            nextQuestion = qs[1],
            nextQuestionButton = false,
            policyText= false))
    }

So the state does move to the next question with the necessary items being visible and invisible, but I am struggling to keep it going to the next questions in the list. I can go from question1 to question2 but not sure how to keep doing that until the end of the list of questions.

So basically, I just want to keep updating the same activity with the new data.

Any help or advice will be highly appreciated.


Solution

  • Not sure if I understood your real problem. Maybe if you share more of your code we could help you better.

    Anyway, I would recommend you to have two states for your view (activity in your case), one state for the question itself containing both yes and no buttons, question text and the right image. And another state for your "move to next" question which contains the question text, button and whatever you want.

    Then your view needs to take care of each state. In the case, you need to deal with one state while dealing against the other state, for example showing one button and hiding the ones you don't need.

    So whenever you click on the yes button, the VM will get the event, check everything and then emit an event back to the View with a new state, and so on.

    It's quite the same thing you did, but using two states will help you to tackle each state and ease off your code