Marc Knaup
08/13/2019, 12:15 PMonPause
or onStop
, e.g. in case the user switches to another application.
The launched coroutine’s scope however cannot be bound to the activity’s lifecycle because the save operation may not have finished by the time the activity gets destroyed. Even worse the whole app may be destroyed or hibernated because there are no activities left, which would abort the save operation.
How would I model that properly?
• The most simple solution I can think of is to block the main thread on onStop
and wait for the coroutine to complete. But that’s somewhat counter-productive 🤔 OTOH that would ensure that if the user switches to another activity they’d not risk seeing stale data because the save hasn’t completed yet.
• Another solution could be a long-running service for any kind of database I/O but that seems unnecessarily complex (and may even need a foreground service?).igor.wojda
08/13/2019, 12:51 PMAndroidX Lifecycle
library (2.1.0-rc01
) that provides viewModelScope
for each ViewModel eg. https://github.com/igorwojda/android-showcase/blob/master/feature_album/src/main/java/com/igorwojda/showcase/feature/album/presentation/albumlist/AlbumListViewModel.ktlouiscad
08/13/2019, 12:56 PMgildor
08/13/2019, 2:10 PMMarc Knaup
08/13/2019, 2:16 PMlouiscad
08/13/2019, 2:17 PMMarc Knaup
08/13/2019, 2:21 PMWorkManager is not intended for in-process background work that can safely be terminated if the app process goes away or for tasks that require immediate execution.(emphasis mine)
louiscad
08/13/2019, 2:23 PMwithContext(NonCancellable) { … }
.Marc Knaup
08/13/2019, 2:25 PMgildor
08/13/2019, 2:30 PMwhich is not a problem if it’s quickExactly, it’s a hack that may work for sure, but one day may cause problems. So repository solves this issue
louiscad
08/13/2019, 2:30 PMgildor
08/13/2019, 2:31 PMdo you mean using a foreground service to keep the app alive while the app repo is still storing dataYes, I think foreground service is really nasty component and not suitable for this case
igor.wojda
08/13/2019, 2:31 PMMarc Knaup
08/13/2019, 2:32 PMgildor
08/13/2019, 2:35 PMigor.wojda
08/13/2019, 2:35 PMgildor
08/13/2019, 2:35 PMMarc Knaup
08/13/2019, 2:36 PMgildor
08/13/2019, 2:36 PMapp is guaranteed some timethere is no such thing as guaranteed time
Marc Knaup
08/13/2019, 2:37 PMgildor
08/13/2019, 2:38 PMonPause
or `onStop`“, would be much better save when something change, not onStopOnly edge cases…or ANR that you cannot avoid because forground service is starting longer than required by startForegroundService() (see issue above)
igor.wojda
08/13/2019, 2:39 PMgildor
08/13/2019, 2:40 PMI mean kill activity before finishing few ms writeWhich is even more rare if you just save on user action (user input, save button etc) instead of waiting onStop
Marc Knaup
08/13/2019, 2:41 PMI believe your problem is original requirement “Now let’s say I have an activity and save data inor `onStop`“, would be much better save when something change, not onStoponPause
gildor
08/13/2019, 2:42 PMThe user would overwrite data he may not wish to overwritewhy so? How is that different from saving while onStop?
Marc Knaup
08/13/2019, 2:52 PMgildor
08/13/2019, 2:52 PMIf I’d save on each change then I’d have to save after every single keystrokejust use debounce()
Marc Knaup
08/13/2019, 2:53 PMgildor
08/13/2019, 2:53 PMMarc Knaup
08/13/2019, 2:53 PMgildor
08/13/2019, 2:53 PMMarc Knaup
08/13/2019, 2:54 PMgildor
08/13/2019, 2:54 PMMarc Knaup
08/13/2019, 2:54 PMgildor
08/13/2019, 2:56 PMAt some point it because quite difficult to understand where data is actually flowing.
And Exception reporting was basically useless.and how would it be easier without Rx?
Marc Knaup
08/13/2019, 2:57 PMgildor
08/13/2019, 2:57 PMno onError has been registeredThis can be handled by global Rx error handler, and also, why you don’t have onError?
Marc Knaup
08/13/2019, 2:59 PMgildor
08/13/2019, 2:59 PMigor.wojda
08/13/2019, 2:59 PMvar quoteJob: Job? = null
...
fun saveData(data) {
quoteJob?.cancel()
quoteJob = CoroutineScope(<http://coroutineContentProvider.IO|coroutineContentProvider.IO>).launch {
delay(200)
db.saveData(data)
}
}
Marc Knaup
08/13/2019, 3:00 PMgildor
08/13/2019, 3:00 PMMarc Knaup
08/13/2019, 3:01 PMgildor
08/13/2019, 3:01 PMMarc Knaup
08/13/2019, 3:03 PMigor.wojda
08/13/2019, 3:04 PMthrottling
and debouncing
debouncing
- Combine bunch a series of sequential calls to a function into a single call to that function. It ensures that one notification is made for an event that fires multiple times e.g. button click
throttling
- Delay executing a function. It will reduce the notifications of an event that fires multiple times e.g. window.scroll, window resizeMarc Knaup
08/13/2019, 3:04 PMgildor
08/13/2019, 3:05 PMMarc Knaup
08/13/2019, 3:08 PMgildor
08/13/2019, 3:08 PMMarc Knaup
08/13/2019, 3:09 PMgildor
08/13/2019, 3:10 PMMarc Knaup
08/13/2019, 3:11 PMgildor
08/13/2019, 3:11 PMlouiscad
08/13/2019, 3:13 PMMarc Knaup
08/13/2019, 3:14 PMlouiscad
08/13/2019, 3:14 PMgildor
08/13/2019, 3:18 PMFlow is still simpler than RxSimpler or aka “not all Rx operators implemented… yet”
Marc Knaup
08/13/2019, 3:19 PMgildor
08/13/2019, 3:19 PMMarc Knaup
08/13/2019, 3:20 PMgildor
08/13/2019, 3:21 PMahulyk
08/14/2019, 3:52 PMrunBlocking
for some saveData()
method in onStop
should be just fine.
BTW - you should be able to save all your data while the viewmodel is active. All user inputs - could be persisted using onSave/onRestore instance state.louiscad
08/14/2019, 3:59 PMrunBlocking
on the main thread is never fine. You're risking your app to be killed because of an ANR if the storage is busy (e.g. while the Play Store installs an update on a device with slow storage, i.e. most cheap devices).Marc Knaup
08/14/2019, 4:00 PMlouiscad
08/14/2019, 4:02 PMMarc Knaup
08/14/2019, 4:03 PM