Office Hours — Today, March 19

Tuesday, March 17

Mark M.
has entered the room
Mar 19
8:25 AM
Mark M.
turned on guest access
8:30 AM
sudokai
has entered the room
Mark M.
hello, sudokai!
how can I help you today?
8:35 AM
sudokai
Hi again Mark.
I'm still building my ViewModel tracking my uploads. What's the best practice to observe different streams of LiveData?
I want to track an upload or an item, but each item can contain pictures
Mark M.
so, do you mean that you have a LiveData for some base upload, plus additional LiveData for each picture upload, or something like that?
sudokai
Ideally I would like to have a single LiveData of the view state
Mark M.
I agree
8:40 AM
Mark M.
what are you using for the actual uploads? OkHttp?
8:40 AM
sudokai
So it's a single centralized upload status bar that shows the state of the upload
8:40 AM
sudokai
Like "Uploading pictures 3/20...."
The upload status bar is for the item (the container)
Then each item has N pictures
Yeah, I'm using OkHttp
Then I'm saving the upload state inside Realm
Mark M.
OK, and you said that you are using LiveData in your ViewModel -- what are you using between OkHttp/Realm and the LiveData? just callback APIs?
sudokai
Mark M.
OK, so Realm is giving you its own LiveData
sudokai
So I have UploadState and PictureUploadState inside realm
And then I use the technique described in the article to get LiveData from Realm
But then I need to combine those in some way to output a single stream of LiveData for the ViewModel
8:45 AM
Mark M.
LiveData is not very powerful. I tend to rely on it for the "last mile", going from a ViewModel to an activity/fragment, and use RxJava or Kotlin coroutines for all the repository/data source work.
however, you should be able to set up what you want with a MediatorLiveData
MediatorLiveData allows you to have it subscribe to N other LiveData and call you when any of those change, so you can apply an update to the MediatorLiveData itself
sudokai
Basically, my realm is set up as this
View paste
open class UploadState(
        var isUploadInProgress: Boolean,
        var itemUuid: String
        var numUploadAttempts: MutableRealmInteger,
        var lastUploadAttemptTs: Long,
        var picturesUploadState: List<PictureUploadState>
): RealmObject()

open class PictureUploadState(
        val pictureUuid: String,
        var numUploadAttempts: MutableRealmInteger,
        var lastUploadAttemptTs: Long
): RealmObject()
Okay I'll check it out
Thanks!
Mark M.
so, in your case, you would have the MediatorLiveData observe each LiveData associated with the overall operation (base + N pictures), and the MediatorLiveData would emit updates to the viewstate based on that overall operation
sudokai
Okay, that makes sense, so I need to create N streams
Stepping back, is this general approach the right one?
Mark M.
yeah, I am assuming that you are getting one LiveData from Realm for each of your states
I have not used Realm much, so I do not know its API very well
sudokai
Would you do it this way or? I'm using LiveData because it's what I know
8:50 AM
Mark M.
in terms of your "stepping back" question... again, I would tend to use RxJava or coroutines with Realm and OkHttp, and have my ViewModel consume those and update LiveData as needed
LiveData is not designed for "heavy lifting", as it were
so, the more complex things get, the amount of work that you will need to do for a 100% LiveData solution will climb faster than the equivalent amount of work for a RxJava/coroutines + LiveData solution
sudokai
So you would emit LiveData from the ViewModel - Fragment communication but use RxJava / coroutines for ViewModel - Realm communication?
Mark M.
yes, though I don't know how well Realm and coroutines get along
(again, I'm not a Realm guy)
Realm and RxJava can work together, though at least a couple of years ago there were some screwy Realm threading issues
sudokai
Tbh, I'm a newbie myself. I would probably just use Room if I started a new project, but I inherited this one.
Realm's entire paradigm seems a bit strange to me
Mark M.
in my case, the project I was on was slowly ripping out Realm and replacing it with Room
sudokai
Though it might just be my own ignorance
We have a lot of weird Realm issues appearing on Crashlytics
Mark M.
I wasn't a huge fan of what I was seeing with Realm, and I really wasn't a fan of the big APK footprint it required
in the hands of a Realm expert, Realm is probably fine -- we were in a similar situation to you, having inherited a Realm-based project, and we were happy to be getting rid of it
8:55 AM
sudokai
I'll check if I can track a single Realm stream. The PictureUploadState is nested inside the UploadState.
That would simplify things a lot. But I doubt it's possible.
Mark M.
¯\_(ツ)_/¯
sudokai
It's tracking the N streams that worries me
Because the user can add pictures to be uploaded while the other stuff is still uploading
And also delete pictures
Mark M.
that sounds like more of a "work queue" model
9:00 AM
sudokai
But I cannot use a single state object to track the entire upload, because each picture has its own upload state, the number of retry attempts, etc.
Mark M.
makes sense
sudokai
I'm offloading the uploads themselves to workmanager from the viewmodel
Mark M.
and in the Worker you are doing the OkHttp calls?
sudokai
Yeah, exactly. So each worker does the OkHttp calls and creates/updates state objects in Realm
Mark M.
so it sounds like you are tracking N pieces of WorkManager work
WorkManager is set up fairly well for that scenario, as I recall
sudokai
Then, from the viewmodel I query Realm and listen to the state object changes
Mark M.
ah, I'd probably monitor WorkManager
though perhaps there is data in Realm that you would need that you would not be getting from your WorkManager results
but, off the cuff, if you are trying to report to the user the results from N pieces of work, to me that's "observe WorkManager" more than "observe Realm"
9:05 AM
sudokai
Yeah, I was just checking your book
LiveData<WorkInfo>
That's promising
Mark M.
right
sudokai
I also see MediatorLiveData
So you launch WorkRequests and keep adding sources to the MediatorLiveData
Nice approach
Mark M.
in your case, if you tag them all the same, getWorkInfosByTagLiveData() will give you a single LiveData that emits a List<WorkInfo>, presumably updating when any single piece of work changes state
that would be an alternative to using MediatorLiveData to handle N individual LiveData per piece of work
sudokai
Then the realm state object could just hold the upload attempts and timestamps and whatnot
But wouldn't be used for stream observation
9:10 AM
Mark M.
yes, probably
I say "probably" just because I'm not 100% clear on your needs, but my guess is that observing WorkManager and perhaps making some Realm queries in response to WorkManager state changes will meet your needs
IOW, the usual caveats apply: your mileage may vary, do not taunt Happy Fun Ball, etc. :-)
sudokai
Thanks! I'll try this approach. Sounds like the most manageable one!
9:30 AM
Mark M.
OK, that's all the time I have for today's chat
the transcript will go up on https://commonsware.com/office-hours/ shortly
the next chat is Saturday at 4pm US Eastern
have a pleasant day, and stay healthy!
sudokai
has left the room
Mark M.
turned off guest access

Tuesday, March 17

 

Office Hours

People in this transcript

  • Mark Murphy
  • sudokai