Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send data from FCM's onMessageReceived() to Fragment?

I'm using Firebase Cloud Messaging to receive data in my app:

class CustomFirebaseMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(msg: RemoteMessage?) {
        val data = msg?.data ?: return
        val name = data["name"] as String
        val age = data["age"]?.toIntOrNull() ?: return
        val bio = data["bio"] as String
        val img1 = data["img1"] as String
        val match = Profile(name, age, bio, img1, null, null)
        Log.d(TAG, "onMessageReceived(): $name is $age")
        val fcmViewModel = ViewModelProviders.of(this).get(FcmViewModel::class.java) // .of() only takes a fragment/activity
        FcmViewModel().match.postValue(match)
        Log.d(TAG, "Value: " + FcmViewModel().match.value.toString()) // null
        super.onMessageReceived(msg)
    }

When I receive the FCM, I want to pass it to my Fragment. I've tried to use LiveData + ViewModel, but unfortunately, postValue() isn't actually changing the data in the ViewModel from the service because I can't instantiate a reference to the ViewModel from a service.

class FcmViewModel : ViewModel() {

    val match: MutableLiveData<Profile> by lazy {
        MutableLiveData<Profile>()
    }
}

class MapFragment : Fragment() {

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            fcmViewModel.match.observe(this, Observer<Profile> { profile ->
            log("${profile.name} is ${profile.age}") // doesn't print
        })
    } 
}

Is there a better way to pass data from FirebaseMessagingService() to my fragment or a way to post data to FcmViewModel() within the FirebaseMessagingService()?

like image 402
Zorgan Avatar asked Jan 02 '20 13:01

Zorgan


1 Answers

With a LocalBroadcastManager marked as deprecated, it' seems like there is no standard way of doing this now.

However LiveData has nothing to do with ViewModels. You can still use LiveData. I would recommend @tyczj's solution which he has commented. Or you can do following.

Create a singleton class which will work as your small event bus framework. This singleton class can have list of LiveData which you need and both Fragment and Service can access instance of LiveData. Service and Fragment can act as a lifecycle owner, so you will not face any problem.

Below is a sudo code

object Events {
    val serviceEvent: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
}

class CustomFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(msg: RemoteMessage?) {
        Events.serviceEvent.postValue(profileObj)
        super.onMessageReceived(msg)
    }
}
class MapFragment: Fragment {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Events.serviceEvent.observe(this, Observer<Profile> { profile ->
            log("${profile.name} is ${profile.age}")
        })
}

You can also create your own subclass of LiveData and control the data updates in LiveData by overriding onActive and onInactive functions

like image 101
Hardik Trivedi Avatar answered Sep 18 '22 22:09

Hardik Trivedi