Search code examples
androidviewmodelandroid-livedata

How to update LiveData and RecyclerView when returning to the previous activity?


I'm learning about Android and ViewModel and to improve knowledge I am developing an Android project, and the objective is to increase and refactor it along with new knowledge. In this moment I'm using just ViewModel, LiveData and Activity (without fragment). The project is a Contact book, in the first screen there is a recyclerview to display the contacts, and in the bottom has a Fab to go to the second screen. In the second screen there are some fields to create a new contact. To save the contacts is used a static attribute. To first screen I create a ViewModel that has a LiveData to update the RecyclerView and in the second screen I create a ViewModel to get the data and send to repository to save statically the contact. I would like to know how it's possible to update the livedata when I save the contact in the second screen so that when you close it and go back to the first screen, the recycler view is updated. I can register the contact, but when I return to the previous screen, the new value is not displayed I apologize if this is a silly question. Here is my code:

AgendaListActivity(MainActivity)

class AgendaListActivity : AppCompatActivity() {
    private lateinit var viewModel: AgendaListViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_agenda_list)

        viewModel = ViewModelProviders.of(this).get(AgendaListViewModel::class.java)

        val observer = Observer<List<Contact>> {
            agenda_list.apply {
                layoutManager = LinearLayoutManager(this@AgendaListActivity, RecyclerView.VERTICAL, false)
                setHasFixedSize(true)
                adapter = AgendaListAdapter(it)
            }
        }

        viewModel.contactList.observe(this, observer)

        activity_agenda_list_fabAddContact.setOnClickListener {
            onClickAddContact()
        }

        viewModel.getContacts()
    }

    override fun onResume() {
        super.onResume()
    }

    fun onClickAddContact() {
        startActivity(Intent(this, ContactFormActivity::class.java))
    }
}

AgendaListViewModel

class AgendaListViewModel: ViewModel() {
    var contactList: MutableLiveData<List<Contact>> = MutableLiveData()
    var contactRepository:ContactRepository         = ContactRepository()

    fun getContacts() {
        contactList.value = contactRepository.getContactList()
    }
}

ContactFormActivity

class ContactFormActivity : AppCompatActivity() {

    private lateinit var name: String
    private lateinit var phone: String
    private lateinit var email: String
    private lateinit var viewModel: ContactFormViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_contact_form)

        viewModel = ViewModelProviders.of(this).get(ContactFormViewModel::class.java)

        activity_contact_form_btnAddContact.setOnClickListener {
            onClickAddContact()
        }
    }

    fun onClickAddContact() {
        getDataFromEditText()
        setDataToViewModel()
        viewModel.saveContact()
        finish()
    }

    fun getDataFromEditText() {
        name  = activity_contact_form_editName.text.toString()
        phone = activity_contact_form_editPhone.text.toString()
        email = activity_contact_form_editEmail.text.toString()
    }

    fun setDataToViewModel() {
        viewModel.setName(name)
        viewModel.setPhone(phone)
        viewModel.setEmail(email)
    }
}

ContactFormViewModel

class ContactFormViewModel: ViewModel() {

    private var name: String      = ""
    private var phone: String     = ""
    private var email: String     = ""
    private var contactRepository = ContactRepository()
    private var contact           = Contact()

    fun saveContact() {
        setContact()
        contactRepository.addContact(contact)
    }

    private fun setContact() {
        contact.setName(name)
        contact.setPhone(phone)
        contact.setEmail(email)
    }

    fun setName(name: String) {
        this.name = name
    }

    fun setPhone(phone: String) {
        this.phone = phone
    }

    fun setEmail(email: String) {
        this.email = email
    }
}

ContactRepository

class ContactRepository {

    companion object {
        var contactList: MutableList<Contact> = ArrayList<Contact>()
    }

    fun addContact(contact: Contact) {
        contactList.add(contact)
    }

    fun getContactList(): MutableList<Contact> {
        return ArrayList<Contact>(contactList)
    }

}

Contact (Model)

class Contact {
    private var name: String = ""
    private var phone: String = ""
    private var email: String = ""

    fun setName(name: String) {
        this.name = name
    }

    fun setPhone(phone: String) {
        this.phone = phone
    }

    fun setEmail(email: String) {
        this.email = email
    }

    fun getName(): String {
        return name
    }
}

Solution

  • If you want to save the contact and refresh your recycler view, you could do the next options:

    1. SetActivityForResult -> Return a boolean to indicate the main activity must be refresh, so you can to fetch data from your viewmodel
    2. Another option is always loadContacts in the resume lifecycle activity, so when you save a contact, then the activity init the onResume lifecycle and fetch data
    3. And another option is to share your viewmodel
    4. Create a singleton repository and use a livedata to update your contacts. The MainViewModel must be observe the repository livedata, for example using Transformations. But I prefer to avoid the singleton repositories with livedatas, also in this case it will works fine.