Office Hours — Today, December 6

Tuesday, December 4

Dec 6
7:25 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:30 PM
Aaron
has entered the room
7:35 PM
Aaron
hey Mark.
Mark M.
hello, Aaron!
how can I help you today?
Aaron
I've been switching over my networking to RxJava and I have numerous questions along those lines
this is going to be a wall of text, so sorry lol, but here goes:
View paste (10 more lines)
1. Your book describes Rx's `ObservableOnSubscribe<T>` as "for cases where we are only actually starting to obtain data for our stream when something subscribes to the Observable, not before." The Javadoc says it's "A functional interface that has a subscribe() method that receives an instance of an ObservableEmitter instance that allows pushing events in a cancellation-safe manner." I can't quite extract your definition from the Javadoc; it sounds like you're saying it's a "cold" Observable and the Javadoc doesn't mention that. Am I misreading the Javadoc? Does its definition entail yours? It makes me nervous that you are getting a meaning from it that I'm not - I must be misunderstanding something...
http://reactivex.io/RxJava/javadoc/io/reactivex/ObservableOnSubscribe.html

2. Also, according to that link, the `ObservableOnSubscribe`'s only method, `subscribe(ObservableEmitter<T> emitter)` is "called for each Observer that subscribes". ...so, the `ObservableEmitter` *is* the subscribed `Observer`, right? I think that's basically how it works, but `ObservableEmitter` is kind of a weird thing to call an `Observer`...

3. I'm trying to understand flatMap()'s inner workings. If I ha
...
Mark M.
first, on the whole, my book's "Rx Basics" chapter is... not great
Aaron
it was brief but helpful. I've used several other sources to complement it
(1) is really the only question that pertains to your book specifically
Mark M.
at the same time, the RxJava documentation, IMHO, is... not great
Aaron
that has been my impression so far
Mark M.
so, with all that in mind, let's plow through your questions
Aaron
OK
Mark M.
ObservableOnSubscribe, despite the name, is not an Observable
7:40 PM
Mark M.
but you use one with things like Observable.create() to create an Observable
the JavaDocs for Observable.create() reference cold observables: http://reactivex.io/RxJava/javadoc/io/reactivex...
so, in the battle of the not-great written works, I'll stand by my not-great over their not-great :-)
"so, the `ObservableEmitter` *is* the subscribed `Observer`, right?" -- not really
ObservableEmitter is the way you deliver objects to observers
there are some levels of indirection in here that is part of the great mystery that is the RxJava implementation
Aaron
yeah...
7:45 PM
Aaron
so it's not really the Observer, but emitter.onNext() is still calling the Observer's onNext(), correct?
Mark M.
I would phrase it more as "triggering" than calling, as I don't know what all is in between those two objects
Aaron
OK
Mark M.
"calling" to me implies that the emitter has a direct reference to the observer, and I don't know if that is the case or not
Aaron
got it
Mark M.
for #3, I think that you're basically correct, though your example (flatMap() to single-String Observables) isn't exactly a recommended practice
the language that you cite for #4 is mostly drawing a comparison between map() and flatMap(), I suspect
to Rx-ify an example from a LiveData presentation I was just watching: suppose that you have an Observable that emits user IDs, based on the user logging in and out of your app
Aaron
in response to #3, slightly tangential, but I am curious what is recommended then, as that exact example was actually provided in more than one "intro" style article
Mark M.
that ties into #4, so let me finish that, and I'll blend in my response to this as part of it
Aaron
OK
Mark M.
so you have this userIdObservable
however, you really need a User object, which you need to load from the database
you have a Room UserDao set up with a loadUser(String userId) method that returns Single<User>
you also have a loadUserRightNowDammit(String userId) method that returns User
7:50 PM
Mark M.
to build an RxJava chain that starts with userIdObservable and emits a User to your subscriber, you have two main options
A. you map() the userId to the User using loadUserRightNowDammit()
B. you flatMap() the userId to the User using loadUser()
so long as you have your threads set up properly with your subscribers, those will have the same net result in the end
however, that's a case where *you* were in control over the API and basically gave yourself two options
now imagine that you're using somebody else's user-management library
you don't control the API -- you get what they give you
if they give you a loadUserRightNowDammit()-style method, you would use map()
if they give you a loadUser()-style method, you would use flatMap()
the developers of the library might intentionally only expose reactive types (e.g., Single<User>), to make it less likely that consumers of the library would accidentally call loadUserRightNowDammit() on an inappropriate thread, such as Android's main application thread
Aaron
OK, keep going but indicate when you are done, as I have a question
Mark M.
so, rolling back to #3, artificially creating observables just to use flatMap() is pointless, as you will be better served with other operators, such as map()
but, *if* you are using something that is exposing a reactive API, that is where flatMap() comes into play
and with that, fire away with questions! when we're done with those, I can return to your list
7:55 PM
Aaron
OK, so, this is just a thought experiment, obviously it would be bad, but,
technically you could also have option (C), in which you map() the userId to the User with loadUser(), and then double-subscribe to the resulting Single<Single<User>> - right?
Mark M.
um, sure, though I don't know of any use case for that
Aaron
yeah, I doubt there is one, it's just a helpful way to verify I get what's happening in both cases
so that's good, I think I get it then
please continue!
Mark M.
in terms of #5, near as I can tell, Reactive Streams is part of a standardization process
RxJava provides an implementation of that, but its own capabilities greatly exceeded the Reactive Streams spec
8:00 PM
Mark M.
personally, outside of toFlowable() for use with LiveDataReactiveStreams, I have not used the Reactive Streams family of classes
so, I can't really answer that one
Aaron
OK. I figured that Subscriber might be too low-level to matter for me right now
that's a good enough answer for me
Mark M.
for #6, you probably want to look at PublishSubject and BehaviorSubject
off the top of my head, BehaviorSubject is probably the closest analogue to MutableLiveData
however, if you don't want the "get only future emissions, not the last one", that's PublishSubject
sorry, typo in that last one
let's try that again
however, if you want "get only future emissions, not the last one", that's PublishSubject
Aaron
OK
Mark M.
in terms of #7, the approach that you are describing is not itself lifecycle-aware
you keep updating the MutableLiveData(?) until you unsubscribe
the LiveData that you get from LiveDataReactiveStreams is lifecycle-aware and will unsubscribe for yout
er, for you
Aaron
ah that makes sense.
8:05 PM
Mark M.
but your one-liner is basically the guts of the implementation, more or less
8:05 PM
Aaron
got it
Mark M.
in terms of your last one -- and bearing in mind the problems you were pointing out with the heap dumps not clearing garbage anymore -- I tend not to use heap dumps to try to track down that sort of thing
I will focus on my types and obvious stuff from libraries
in the end, a random String is not likely to be leaked in isolation
Aaron
yep, ok, it seemed like a hopeless endeavor anyway
Mark M.
something is holding onto something that is holding onto something that is holding onto something that is holding that String, and you are leaking the very first "something"
and that "something" is more likely to be recognizable
the only low-level types I'll worry about are bitmaps, 'cause they can get huge
I think that covers your list
Aaron
yep, that's great, thank you,
let me throw in a couple quick follow ups before going. I didn't have time to properly think this one through so it's going to be poorly formulated, but
8:10 PM
Aaron
I was trying to think about how RxJava switchMap() is analogous to LiveData switchMap(), but was having a tough time, as I think the similarity is fairly abstract
is it obvious to you how to formulate the analogy?
Mark M.
I have to keep looking up on Google to understand the difference between flatMap() and switchMap() just within the RxJava world
let alone comparing to LiveData's switchMap()
Aaron
yeah, ok, don't worry about it then
Mark M.
they are analogous insofar as they both map a simple thing to a reactive thing
compared to map() which maps a simple thing to a simple thing
Aaron
no worries :p
last thing, I can probably figure this out myself after the chat but just want to ask before I go, this was an example of the flatMap usage I was talking about
imagine this method returns search engine URL results based on the query:
View paste
query("Hello, world!")
    .flatMap(new Func1<List<String>, Observable<String>>() {
        @Override
        public Observable<String> call(List<String> urls) {
            return Observable.from(urls);
        }
    })
    .subscribe(url -> System.out.println(url));
the article is putting forth that flatMap() is necessary to accomplish that and print one URL at a time
how would you rewrite it to use map()?
Mark M.
I wouldn't
well, I suppose it depends
8:15 PM
Mark M.
query() is returning a Single<List<String>> or something?
Aaron
yes
sorry
Observable<List<String>> as per the example but should be functionally the same I think
Mark M.
and you are looking to consume each URL individually for one reason or another
Aaron
what he says is that the subcriber's role is to consume, not to mutate, so you wouldn't want to break the List apart inside the subscriber
and yes, if you want to get each one individually that flatMap would be needed
Mark M.
this may be an RxJava 1.x example, as there is no from() on Observable
Aaron
yes, it is 1.x
Mark M.
ah
take anything related to RxJava 1.x with a grain of salt when it comes to RxJava 2.x
the equivalent in RxJava 2 would be fromIterable()
I think there is another operator that could flatten the List<String> to String events without the flatMap()
8:20 PM
Mark M.
though I confess that I am not seeing it
Aaron
hm, OK I'll research it further and formulate a better question for next time if needed
Mark M.
but I will agree that splitting an object into multiple downstream objects may require a flatMap() created using some simple Observable factory method, such as fromIterable()
your question isn't bad, it's just that I think that there's a simpler solution out there
Aaron
do you agree that map() would not suffice?
Mark M.
map() is 1:1
you basically want 1:N (1 list to N strings)
and map() can't do that
Aaron
yeah, OK, I think we are on the same page about it
mainly wnated to make sure about what you said earlier, "artificially creating observables just to use flatMap() is pointless, as you will be better served with other operators, such as map()", that this would not be a case in which it's pointless
although the chat history is scrolling off screen and that may have been in response to something else
Mark M.
unless there is some other solution, other than flatMap(), for 1:N
Aaron
OK, that is all I've got
8:25 PM
Aaron
roger that
alright thanks! that was really helpful
Mark M.
you're welcome!
Aaron
I might have 1-2 more during the next chat but that was most of it
Mark M.
sounds good
Aaron
thanks - have a good night
Mark M.
you too!
Aaron
has left the room
8:30 PM
Mark M.
turned off guest access

Tuesday, December 4

 

Office Hours

People in this transcript

  • Aaron
  • Mark Murphy