3

How to use data from onActivityResult in MVVM architecture? I need to add an item to the RecyclerView that is subscribed to receive data from the ViewModel. How can I send data from onActivityResult to the ViewModel class and then update my list? If I add data to the adapter immediately from the onactivityresult method, nothing happens. I need any help on this issue

Activity class:

class ContactsActivity : AppCompatActivity(), ContactsListener {
    private val TAG = "ContactsActivity"

    @Inject
    lateinit var factory: ViewModelProvider.Factory
    lateinit var contactsViewModel: ContactsViewModel


    companion object {
        const val ADD_CONTACT_REQUEST = 200
    }

    private lateinit var mAdapter: ContactsAdapter

    @SuppressLint("WrongConstant")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        toolbar_contacts.title = getString(R.string.contacts_toolbar_title)

        add_new_contact_btn.setOnClickListener {
            val intent = Intent(this@ContactsActivity, AddContactActivity::class.java)
            startActivityForResult(intent, ADD_CONTACT_REQUEST)
        }

        DaggerContactsActivity_ContactsComponent.create().inject(this@ContactsActivity)
        contactsViewModel = ViewModelProviders.of(this@ContactsActivity, factory).get(ContactsViewModel::class.java)
        contactsViewModel.getContactsList().observe(this@ContactsActivity, Observer {

            mAdapter = ContactsAdapter(this@ContactsActivity, it)
            recycler_contacts.layoutManager =
                LinearLayoutManager(applicationContext, OrientationHelper.VERTICAL, false)
            recycler_contacts.adapter = mAdapter
            recycler_contacts.setHasFixedSize(true)

            mAdapter.sortByName()

        })
    }

    // Dagger create
    @Component (modules = [ContactsModule::class])
    interface ContactsComponent {

        fun inject (activity: ContactsActivity)
    }

    @Module
    abstract class ContactsModule {

        @Binds
    abstract fun bindViewModelFactory(factory: ContactsViewModelFactory): ViewModelProvider.Factory
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
            if (resultCode == ADD_CONTACT_REQUEST && resultCode == RESULT_OK) {
                val firstName: String? = data?.getStringExtra(AddContactActivity.EXTRA_FIRST_NAME)
                val lastName: String? = data?.getStringExtra(AddContactActivity.EXTRA_LAST_NAME)
                val phone: String? = data?.getStringExtra(AddContactActivity.EXTRA_PHONE)
                val email: String? = data?.getStringExtra(AddContactActivity.EXTRA_EMAIL)
                val notes: String? = data?.getStringExtra(AddContactActivity.EXTRA_NOTES)

                val contacts = Contacts(firstName = firstName.toString(), lastName = lastName.toString(), phone = phone.toString(),
                    email = email.toString(), notes = notes.toString(), images = "")

                contactsViewModel.get(contacts = contacts)
            }
        }

    override fun setupContactsList(contactsList: ArrayList<Contacts>) {

        mAdapter.setupContacts(contactsList = contactsList)
    }
}
Infernal
  • 202
  • 3
  • 13

2 Answers2

1

IN MVVM Architecture, you don't need to exchange data using Activity's onActivityResult. Instead, let target Activity's UI bind to ViewModel's LiveData which further points to same data source (e.g. sqLite) that is updated by another activity (via its own ViewModel).

Birender Singh
  • 513
  • 6
  • 16
  • I don't have another data source. I get the list from the Api and show it in the RecyclerView. After that, I need to temporarily add another item to this list that the user adds. This element will be displayed until I close the app for the first time. But I will also send this item to the server and add it to the list. The next time the user opens the app, they will get a list from the Api with the new element added. – Infernal Jan 08 '20 at 17:31
  • ok, i think you can do this. The very first time when your Activity needs data, its attached Viewmodel fetches from API (on init) and updates LiveData objects which in turn updates RecyclerView with Data binding. Later, when user enters data manually, pass on this data to ViewModel to invoke API. On API success, update LiveData object which auto updates RecyclerView with new entry. Now, if your flow has different Activity to add new data, i think you should have common ViewModel attached to both Activities. That way data will be auto updated irrespective of navigation flow. – Birender Singh Jan 09 '20 at 07:03
0

MVVM enables two way binding. Just update the list when you are finishing or clearing the activity whose onActivity result you have overriden.

The data is already subscribed in your previous activity and it will get the update as soon as the other activity updates the list. The ViewModel would be shared between both the activities.

Take a look at the working of MVVM with shared instance : https://www.google.com/url?sa=t&source=web&rct=j&url=https://github.com/android/architecture-components-samples/issues/29&ved=2ahUKEwjn0ZWEzvPmAhUxzDgGHXhuBUsQFjAAegQICRAE&usg=AOvVaw36xQIOfJIp4abIODjXrz6S

Anup Lal
  • 59
  • 1
  • 12
  • 3
    This is impossible to implement. When the second Activity passes the data and is destroyed the ViewModel will call the onCleared() method and the first Activity will get the original list again – Infernal Jan 08 '20 at 17:25