Dec 11 | 7:25 PM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Dec 11 | 7:45 PM |
Aaron | has entered the room |
Mark M. |
hello, Aaron!
|
Mark M. |
how can I help you today?
|
Aaron |
hello Mark, I have 3 questions today, here they are:
|
Aaron |
View paste
(2 more lines)
|
Mark M. |
"First, have I understood that correctly?" -- yes, though there is nothing stopping you from disposing of the Rx subscription yourself in onCleared() of the ViewModel
|
Mark M. |
"if all I were using Rx for in my repository were `Single` Retrofit calls, as far as I can tell, LiveDataReactiveStreams would offer no additional advantage versus a MutableLiveData" -- if all you were using is Rx, LiveDataReactiveStreams probably doesn't exist in your app, as you would not be pulling in the LiveData stuff, and certainly not the LiveData/Rx bridge dependency
|
Mark M. |
OK so far?
|
Aaron |
for the second part, the question is, if all i were using _Rx for_ were the network calls - not implying that I am not also using LiveData
|
Dec 11 | 7:50 PM |
Aaron |
using Rx to construct the viewstate that gets wrapped in a LiveData to feed the UI
|
Aaron |
is the idea.
|
Aaron |
the key part of the question is about Singles as opposed to something like a Flowable where stream processing would be ongoing
|
Aaron |
since a Single completes the subscription after the first value is emitted, as far as I can tell, LiveDataReactiveStreams won't do much for you, if you are only using Singles, since you won't have any ongoing emissions
|
Aaron |
does that make sense?
|
Mark M. |
well, not really
|
Mark M. |
you use LiveData to get the reactive events to the UI layer, so it is lifecycle-aware
|
Mark M. |
it does not matter whether there is zero, one, or ten million reactive events
|
Mark M. |
nor does it matter whether the events are triggered by disk I/O, network I/O, Bluetooth I/O, or anything else
|
Mark M. |
you don't have to use LiveDataReactiveStreams to pipe Rx data into LiveData
|
Mark M. |
but similarly, there is nothing intrinsically wrong with doing so, even for Single
|
Mark M. |
if the subscriber of the Single is not the UI layer (via a ViewModel), then LiveDataReactiveStreams has no meaning
|
Mark M. |
so, for example, if the Single is being used by a service for a sync operation, there is no LiveData and no need for LiveDataReactiveStreams (or any other Rx -> LiveData pipeline)
|
Dec 11 | 7:55 PM |
Mark M. |
Rx makes a distinction between the numbers of events: Observable, Single, Completable, etc.
|
Mark M. |
LiveData doesn't, in large part because it is really just a value holder with a callback mechanism
|
Mark M. |
so, I think it is a mistake to say that there is no value in using LiveDataReactiveStreams with a Single
|
Mark M. |
you don't have to use it, and I suspect in many cases you'll do something else anyway (e.g., your MutableLiveData), but it's not completely insane to use it, either
|
Mark M. |
anything else on #1 before I move on to #2?
|
Aaron |
hmm, something is still off with my understanding, I guess another way to state my question is this: before I included Rx at all, I was also constructing a MutableLiveData in my repository (the same thing I am doing with Rx now), the only difference was, I was doing it with MediatorLiveData and LiveData transformations instead of Rx. but in both cases I was construcitng the MutableLiveData in my repository and exposing it to the ViewModel, and subsequently the UI. so the point where I get confused is, there didn't seem to be any lifecycle issues before, and since the repository is exposing the exact same thing now, it seems like there shouldn't be lifecycle issues now, and if there aren't any, then I guess I don't really understand what LiveDataReactiveStreams does, then
|
Mark M. |
well, it eliminates the MutableLiveData
|
Dec 11 | 8:00 PM |
Mark M. |
and it handles the unsubscribe operation for you, so your ViewModel does not have to worry about it
|
Mark M. |
you chose to use MutableLiveData, which is a reasonable choice, but it is not a requirement of using Rx with LiveData
|
Aaron |
(thinking and typing)
|
Mark M. |
TimeMachine/RoomFTS, Diceware/Repository, Trips/RxLifecycle, Diceware/Pwned, and other samples in "Android's Architecture Components" shows how to use Rx with LiveData, generally without your own MutableLiveData
|
Aaron |
so I understand the eliminating the MutableLiveData part, that makes total sense, but I don't think I fully grasp what the unsubscribe operation entails, then. I thought it was something like this: Rx chains only execute when there is a subscriber. so LiveDataReactiveStreams makes sure you don't do redundant background work when the UI can't receive updates, by taking away that subscriber when the UI cannot do so. so that was where I was bringing in the distinction between Single and Flowable, because my understanding was that a Flowable represents ongoing work where there is a continuous subscription, versus a Single where the subscription starts and then immediately ends after the single event
|
Aaron |
and no subscription = no need to unsubscribe
|
Aaron |
I just can't pin down the exact place where I am misunderstanding
|
Dec 11 | 8:05 PM |
Mark M. |
you certainly need to dispose() your Single subscription
|
Mark M. |
every call to subscribe() on an Rx type returns a Disposable
|
Mark M. |
you need to call dispose() on it at some point, when you are done
|
Mark M. |
that does not happen automatically for any Rx type
|
Aaron |
ok, well I certainly misunderstood that, I thought you only needed to dispose the subscription if you chose to hold onto the disposable
|
Mark M. |
nope
|
Mark M. |
now, I have been sloppy about that
|
Aaron |
I see
|
Mark M. |
one of the many Rx things that I will be cleaning up as part of the Great Book Rewrite
|
Aaron |
tell you what, maybe if you could skip to question #3, some of this will be clarified in the process of working on that question
|
Mark M. |
before I forget, if you want Lint to yell at you about Rx hiccups like this, check out rxlint: https://bitbucket.org/littlerobots/rxlint
|
Aaron |
discussing in terms of concrete examples in my code will probably help
|
Aaron |
OK, thanks, I'll check it out
|
Mark M. |
I think the standard is to use Schedulers.io() for network I/O, not Schedulers.computation(), though that's really your call
|
Dec 11 | 8:10 PM |
Aaron |
so I specified Schedulers.io() as part of my Retrofit builder call, as the default
|
Aaron |
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
|
Aaron |
what I am (attempting) to do there, is switch to the computation thread for the map call
|
Aaron |
should the map transformation stay on the io thread?
|
Mark M. |
unless that map work will be *really* slow, the overhead of the thread switch isn't worth it IMHO
|
Aaron |
since it is a data transformation and not really I/O anymore,
|
Aaron |
^ was my reasoning
|
Aaron |
OK, got it
|
Mark M. |
if the data transformation is expensive (e.g., image processing), then that's reasonable
|
Aaron |
understood
|
Mark M. |
as you don't want to tie up the I/O thread, perhaps
|
Mark M. |
I think you are the first developer that I have seen use Flowable -- the *vast* majority of RxJava work seems to be based on Observable more so than Flowable
|
Mark M. |
to be clear, I mean "I have seen use Flowable directly" (versus toFlowable() calls en route to something else, such as via LiveDataReactiveStreams)
|
Mark M. |
there's nothing particularly wrong with Flowable, but your choice is unusual, and it's the sort of choice that you'll want to be able to defend in an interview or code review
|
Mark M. |
I would not have the repository expose LiveData -- I would have it expose Rx types and have the viewmodel do the LiveData work
|
Aaron |
I see, some of the documentation I read about Rx1 vs Rx2 say that Flowable should be the default now unless you have a reason not to, as it handles backpressure automatically (not that this simple stuff is necessarily going to create backpressure), and since I did not have a particularly strong reason, that's why I used it
|
Aaron |
that info may be inaccurate
|
Dec 11 | 8:15 PM |
Aaron |
or perhaps, the work being simplistic enough that it's not going to create backpresure, *is* a good enough reason to use Observable
|
Mark M. |
I'm more going by what I see in blog posts, Stack Overflow questions, presentations, and the like
|
Aaron |
ok, I'll research it further
|
Mark M. |
those would be my comments on that code, from a quick scan of the Rx bits
|
Aaron |
hmm, yes, it seems like that advice is an oversimplification, this page is not so black and white on it
|
Aaron | |
Aaron |
I'll read up on it
|
Aaron |
OK, thanks for that
|
Mark M. |
there are probably teams out there that have standardized on Flowable, for various reasons
|
Mark M. |
and, in terms of the app itself, there's probably nothing wrong with your use of it
|
Aaron |
yeah, I hear what you are saying though
|
Aaron |
needs to be a more defensible choice, whatever it is
|
Mark M. |
where if you lack a defense, take the default, which right now is Observable
|
Dec 11 | 8:20 PM |
Aaron |
in my defense, I was trying to take the default but it seems like I was misinformed about what the default is :p good to know
|
Aaron |
OK, thanks for all that, very helpful as always
|
Mark M. |
you're welcome!
|
Aaron |
LiveDataReactiveStreams still has not clicked for me, but hopefully once I go over your comments and think about it harder it'll click
|
Aaron |
don't have anything else for now - thanks and have a pleasant evening
|
Mark M. |
the samples I cited above all use LiveDataReactiveStreams and so might be worth examining
|
Mark M. |
you too!
|
Aaron |
yes, I will do that
|
Aaron |
night
|
Aaron | has left the room |
Dec 11 | 8:25 PM |
Mark M. | turned off guest access |