androidkotlinmvvmandroid-gpslocation-services

How can i push location data from LocationService to HomeViewModel?


I'm trying to push location data from LocationService to HomeViewModel. I was trying to use Dagger to inject this data, but the value is always null. I don't have any idea how to do it.

My LocationService Code:

class LocationService: Service() {

    private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    private lateinit var locationClient: LocationClient

    private val _locationLiveData = MutableLiveData<Pair<String, String>>()
    val locationLiveData: LiveData<Pair<String, String>> = _locationLiveData

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        locationClient = DefaultLocationClient(
            applicationContext,
            LocationServices.getFusedLocationProviderClient(applicationContext)
        )
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action) {
            ACTION_START -> start()
            ACTION_STOP -> stop()
        }
        return super.onStartCommand(intent, flags, startId)
    }

    private fun start() {
        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Tracking location...")
            .setContentText("Location: null")
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setOngoing(true)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        locationClient.getLocationUpdates(5000L)
            .catch { e-> e.printStackTrace() }
            .onEach { location ->
                val lat = location.latitude.toString()
                val long = location.longitude.toString()

                _locationLiveData.postValue(Pair(lat, long))
                Log.d("LocationT", "LocationService: " + (locationLiveData.value?.first ?: "Dupa0"))

                val updatedNotification = notification.setContentText(
                    "Location: $lat, $long"
                )

                notificationManager.notify(1, updatedNotification.build())

            }.launchIn(serviceScope)

        startForeground(1, notification.build())

    }

    private fun stop() {
        stopForeground(true)
        stopSelf()
    }

    override fun onDestroy() {
        super.onDestroy()
        serviceScope.cancel()
    }

    companion object {
        const val ACTION_START = "ACTION_START"
        const val ACTION_STOP = "ACTION_STOP"
    } }

I also leave link to this projecy on Github: https://github.com/DawidSiudeja/RunTracker/tree/main/app/src/main/java/com/example/runtracker


Solution

  • Create the variables inside a companion object block of your service

    class LocationService: Service() {
    
        private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        private lateinit var locationClient: LocationClient
    
        companion object{
        val locationLiveData = MutableLiveData<Pair<String, String>>()
         }
     }
    

    And the in your activity/fragment observe it as

    class TrackingFragment : Fragment(R.layout.fragment_tracking) {
    
       override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val mapViewBundle = savedInstanceState?.getBundle(MAP_VIEW_BUNDLE_KEY)
            mapView.onCreate(mapViewBundle)
            subscribeToObservers()
      }
    
       private fun subscribeToObservers() {
            LocationService.locationLiveData.observe(viewLifecycleOwner, Observer {
                updateTracking(it)
            })
      }
    
      private fun updateTracking(Pair<String,String>){
       //use the lat lng value to update the map
     }
    
    }