1

I have 2 fragments in my app. when the user clicks on a button in the first fragment, the second fragment gets added so that the user can insert some data. and then it gets closed and gives the inserted data back to the first fragment. I've used ViewModels for this communication between fragments.

    collectionsEditedViewModel = new ViewModelProvider(getActivity()).get(CollectionsEditedViewModel.class);
    collectionsEditedViewModel.isEdited().observe(getViewLifecycleOwner(), new Observer<Bundle>() {
        @Override
        public void onChanged(Bundle bundle) {
        }
    });

the communication is working properly. but the point is that how can I define the scope of this communication within the fragments. currently I'm using getActivity() as ViewmodelStoreOwner which causes the set data to be redelivered to the first fragment whenever it is reopened. how can I solve this issue?

Soheil
  • 587
  • 4
  • 20

1 Answers1

1

I believe for communication between Fragments, via the Activity is the way to go, so you're in the correct path.

One thing you could do is use a SingleLiveData class, which essentially is like LiveData but after its value is set, it's nullified, so only the first observer gets it:

class SingleLiveData<T> : MutableLiveData<T>() {

    private val mPending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<T>) {

        if (hasActiveObservers()) {
            Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
        }

        // Observe the internal MutableLiveData
        super.observe(owner, Observer { t ->
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }

    companion object {
        private val TAG = "SingleLiveData"
    }
}

Then you can simply call: singleLiveData.call() for a "set and destroy" and thus, forget your value after the first use! Class retrieved (and been using in my projects for years) from: https://stackoverflow.com/a/46862551/

  • thanks. but it is written in Kotlin. how can I use it in my java code?! – Soheil Apr 16 '20 at 16:39
  • Kotlin is designed with Java Interoperability in mind, so as long as your project supports Kotlin (you can just add the necessary plugins easily: https://developer.android.com/kotlin/add-kotlin), you'll be able to define a variable in Java and use with the exact same call: singleLiveData.call(); It's also a nice opportunity to see the merits of Kotlin and write your next classes in it! – Orestis Gartaganis Apr 17 '20 at 09:13