-
Notifications
You must be signed in to change notification settings - Fork 363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run GPSTest as foreground Service when in background #299
Comments
As mentioned in #306, users would also like to be able to log to Android Studio and eventually files when the screen turns off - this is the same issue. |
Yeah, thanks for replay on Play Store, I personally absolutel support this topic, the way it is implemented in GPS Locker application for example! (duplicate my review) |
Related to implementing ViewModel and Service: |
Given the most recent Android architecture principles and tools, it seems like the following is the best architecture:
This design is discussed here, with the below demo app currently using DataStore is a possible alternative to Room, although with some of the more complex metadata it seems like Room is a better option. |
Good example of LifecycleService: Some other good resources:
|
I've created a demo here (based on Google's code sample) in the And an article covering implementation: |
Here's a good example showing StateFlow with loading, etc. states: ...from this YouTube video: See also: Using MutableStateFlow without a backing private variable: With Jetpack Compose: |
Good example of managing service restarts using KTX: And example of music service in background using Kotlin: |
Another possibility is to wrap the location listener in its own LocationRepository (e.g. instead of using Room). Some guidance in this direction:
Guidance on converting callback APIs to flow: Example of using Kotlin and LiveData with LocationManager/LocationRepo design, but uses PendingIntents - maybe we could convert this to Flow (?):
There is actually a snippet in this article: ...that points to this Gist: ...which is close to what we want: // Implementation of a cold flow backed by a Channel that sends Location updates
fun FusedLocationProviderClient.locationFlow() = callbackFlow<Location> {
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
result ?: return
try { offer(result.lastLocation) } catch(e: Exception) {}
}
}
requestLocationUpdates(createLocationRequest(), callback, Looper.getMainLooper())
.addOnFailureListener { e ->
close(e) // in case of exception, close the Flow
}
// clean up when Flow collection ends
awaitClose {
removeLocationUpdates(callback)
}
} EDIT - the full code for the above snippet is in https://github.com/googlecodelabs/kotlin-coroutines/blob/master/ktx-library-codelab/step-06/ |
A good video visually explaining the differences between the different types of Flows with animations, in context of updating locations on a map: And the corresponding repos: |
Here's an article I wrote on wrapping the location listener in its own LocationRepository with Kotlin callbackFlow: Link to example on GitHub is in the article. I'm using this pattern in GPSTest. |
This is a major overhaul of the app internals to support a foreground service (i.e., a notification that shows current GNSS status even when the main Activity UI is not showing). This involves moving all the API listeners for GNSS events into their own "manager" classes based on Kotlin callbackFlow that exist the entire lifecycle of the app, so the various app components (Fragments, ViewModels, Activity, Service) can all receive updates from this single source. This bumps minSdkVersion to Android N (24) so we we don't need to deal with the legacy GPS* APIs anymore, which greatly simplifies the data processing within the app. * Convert Activity and Fragments to Kotlin * Add service with notification * Remove legacy GPS* APIs (pre-Android N) * Convert all location / GNSS API registrations to data managers based on Kotlin callbackFlow as detailed in https://barbeau.medium.com/kotlin-callbackflow-a-lightweight-architecture-for-location-aware-android-apps-f97b5e66aaa2. * NMEA * Location * GNSS measurement * Antenna * Nav message * Sensor (orientation) * Add view binding to fragments * Fix filter bug - it currently shows # signals being filtered, not number satellites (doesn't match # Sats field) * Move aggregation of signals to satellites into Flow/ViewModel. * Change Status to Composable - Use LiveData in ViewModel instead - see https://bladecoder.medium.com/kotlins-flow-in-viewmodels-it-s-complicated-556b472e281a that says don't use Flows in ViewModels. Closes #299 Closes #492
Summary:
GPSTest was originally implemented to remaining running in the background when you press the Home key. As discussed in #237 and #297, this has been interpreted to be a feature, not a bug, as it can be helpful to prime GPS in some situations.
However, given the advances in Android since 1.5, background execution should be overhauled to the current Android best practices, which means running it as a foreground Service when in the background. This will allow consistent behavior across devices and a clear notice to the user that GPSTest is still running in the background.
Some UI decisions need to be implemented here, including whether we prompt the user to ask if they want to continue running GPSTest in the background at some point, or just invert the default option and always have GPSTest stop running when the user puts the app in the background unless the user enables a setting to run in the background.
Steps to reproduce:
Start GPSTest and hit the Home button
Expected behavior:
Give me some notice that it's running in the background, and use an Android foreground Service
Observed behavior:
App simply doesn't de-register the LocationListener, which on some devices means it continues running in the background, while on other devices it will be killed.EDIT Dec 10, 2020 As of ae93b7f, the LocationListener is always unregistered in Activity onPause().Device and Android version:
N/A
The text was updated successfully, but these errors were encountered: