3

I have a project, in which I have successfully implemented location tracking feature, and is working perfectly. I am tracking users current location using fused location provider in every 30 seconds.(tracking starts when MainActivity started).

Now I am planning to update that project with newly introduced android architecture components. But I don't know how to implement location tracking with view model.Where is the right place to start location tracking, in MainActivity or Application class? Should I use ViewModel or AndroidViewModel? How to achieve this.

2 Answers2

6

The correct way would be to have a TrackingRepository where you do all calculations in a background thread of the device location. Create a MutableLiveData where you will assign the location. Then update its value using postValue() or setValue(). Write a public getter for this MutableLiveData. This repository will be your location API.

Then your ViewModel should call the method of your repository and assign its result to a LiveData variable of the ViewModel. Then in your Fragment/Activity observe the liveData of your ViewModel. Just as the Guide to App Architecture does.

Remember to use dependency injection which really helps with the new architecture.

Damia Fuentes
  • 5,308
  • 6
  • 33
  • 65
  • 1
    I am confused about, where to ask location permissions and from where to start the service, can you please provide some sample code? –  Dec 10 '17 at 11:58
  • You need to ask the location permissions in the UI, but access the device location through the repository. About from where to start the service, do not really know. Refer to this post although is not answered yet (https://stackoverflow.com/questions/47265685/what-is-the-right-place-to-start-a-service-in-mvvm-architecture-android) – Damia Fuentes Dec 11 '17 at 10:02
  • 2
    Is there a working example of this setup? It would be great to see a working example ...I plan on doing a test either way. – Codeversed Jul 03 '18 at 02:26
  • But `FusedLocationProviderClient` requires `Context` to be instantiated. How can we provide `Context` to it? – Abdul Mateen Aug 29 '19 at 10:40
  • Use the ApplicationContext instead the Activity Context – Kitesurfer Feb 04 '20 at 12:45
1

After few hours of try, finally I could find the solution.

First create a variable inside the LocationRepository.

val currentLocation = MutableLiveData<Location>()

Inside the LocationCallBack (onLocationResult)

currentLocation.postValue(locationResult.lastLocation)

Thereafter in the ViewModel class again

val currentLocation = MutableLiveData<Location>()

and

fun currentLocation(): MutableLiveData<Location>
{
    currentLocation = myLocationProvider.currentLocation
    return currentLocation
}

at least you have observe the ViewModel's MutableLiveDate in your Activity/Fragment

myLocationProvider.currentLocation.observe(this, Observer { currentLocation ->
            currentLocation?.let {
                //Your code here
            }
})

EDIT You have to start the the LocationCallback with suspendCoroutine, GlobalScope and UiDispatcher.

PeterPazmandi
  • 533
  • 10
  • 13
  • 3
    It's a good practice to encapsulate the MutableLiveData so that the View cannot set a new value. ```var _currentLocation = MutableLiveData() ``` this is private to be used in the ViewModel ```val currentLocation = LiveData() get()= _currentLocation``` this is the one to be observed by the View – Eliza Camber Jun 27 '19 at 09:20
  • @ElizaCamber yes, true. I modified my comment, thanks – PeterPazmandi Jun 29 '19 at 06:03
  • @inspire_coding that's still not what @Eliza said. `currentLocation` should be declared as `private val mCurrentLocation=MutableLiveData()` (notice the private). And then the exposed (public) value should be immutable (a LiveData, NOT a MutableLiveData) => `val currentLocation: LiveData = mCurrentLocation`. – OroshiX Jun 30 '22 at 15:05