I'll explain my problem in more detail. I have thi...
# rx
i
I'll explain my problem in more detail. I have this in a class (more specifically Android's view model though this doesn't seem relevant)
Copy code
private val dealerAction: Single<DealerAction> = carDealersRepo.selectedCarDealer()
    .map {
        it.toDealerAction()
    }

val dealerButtonTitle: LiveData<String> = dealerAction
    .map { it.toButtonTitle() }
    .toObservable()
    .toLiveData()
When I navigate to a new screen, I change carDealersRepo's underlaying data. When I navigate back, I want that this view model re-fetches
selectedCarDealer
z
The
selectedCarDealer()
method won’t be executed again, but the single it returns should be subscribed to again.
i
but I put a breakpoint in the code and it doesn't stop there again
Copy code
override fun selectedCarDealer(): Single<Optional<CarDealer>> =
        (preferences.getObject(SELECTED_CAR_DEALER, CarDealer::class.java)?.let {
            Optional.Some(it)
        } ?: Optional.None).let{ Single.just(it) }
z
If you want to invoke the function again, do something like
dealerAction = Single.defer { carDealersRepo.selectedCarDealer() }
i
aha! will try it out
z
Right, so the Single that is being resubscribed is your
Single.just
.
The
selectedCarDealer
method doesn’t magically get executed again
i
awesome it works now! Thank you!! ❤️
z
I think you probably want to change your implementation of
selectedCarDealer
though, to get the behavior you’re expecting. Something like:
Copy code
override fun selectedCarDealer(): Maybe<CarDealer> =
  Maybe.fromCallable {
    preferences.getObject(…)
  }
i
that probably makes sense
z
Wrapping some computation in
just
is usually a smell, since you usually want the computation performed on subscription.
i
right, the problem is the
just
. If it was
create
, it would work, I assume
👍 1
z
(and
Maybe<Foo>
is semantically equivalent to
Single<Optional<Foo>>
with less typing)
i
yep, changing it now
and how do I get notified about whether the result is a value or
null
? in
map
I get only the success value
I need to handle the null explicitly, if there's no selection yet, the button gets a title for that
it seems that
Maybe
isn't made for that 😕
Ok, I changed
selectedCarDealer()
to this:
Copy code
override fun selectedCarDealer(): Single<Optional<CarDealer>> =
    fromCallable {
        Optional.from(preferences.getObject(SELECTED_CAR_DEALER, CarDealer::class.java))
    }
from an architecture perspective this seems bad though. I shouldn't have to depend on the implementation of
selectedCarDealer()
🤔
z
and how do I get notified about whether the result is a value or
null
? in
map
I get only the success value
Ah, then
Single<Optional>>
is the way to go
👍 1
from an architecture perspective this seems bad though. I shouldn’t have to depend on the implementation of selectedCarDealer()
It’s pretty common for methods that return `Single`s that perform some computation to do that computation on subscription, because
Single
typically represents asynchronous computation. The fact that this particular method implementation doesn’t actually do anything asynchronous and always returns immediately is also an implementation detail, but it’s the more anomalous one.
i
I get that, but still... I should not have to think about how an interface is implemented, even if it's corner cases possibly.
z
In other words, the use of
Single
as the return type here implies that this function needs to do some asynchronous work (that’s the whole point of
Single
). The way for
Single
to do asynchronous work is by kicking it off on subscription, so it’s natural to expect that any work it does will be performed on subscription.
I should not have to think about how an interface is implemented
I agree. The point I’m trying (badly) to communicate, is the fact that your interface uses
Single
at all implies that work is being done on subscription, and not just when your method is called. That’s basically the contract of
Single
. That said, if you really don’t trust your implementations to follow this convention, you can just wrap it in a
Single.defer
. But it would be better to make your implementation behave in a less surprising way to begin with, since this might trip up other callers in the future as well.
i
but what if I'm passing e.g. a mock repo for unit tests, where it makes sense to use
.just
z
If your test doesn’t need to change the value, then that’s fine. I use
just
in tests all the time, it’s great for that. But in that case you’re hardcoding a value, not computing it from some real world resource.
i
I should have said integration tests... 😛
hmm
z
If the value can never change, then using
just
is fine.
i
well, I get the reasoning of what you're saying but it still doesn't feel 100% clean from an architectural point of view. "Don't make assumptions" etc. etc.
z
Another question though: since this value evidently can change over time, why are you using
Single
instead of
Observable
?
i
but thanks a lot in any case for the explanations
hmm... I've modeled all the api and repo calls as singles
z
well, I get the reasoning of what you’re saying but it still doesn’t feel 100% clean from an architectural point of view. “Don’t make assumptions” etc. etc.
Like Jake said, this is the default behavior for
Single
. Retrofit does this too: if you have a method that returns a
Single
, the network request will be performed every time you subscribe to the single, not every time you call the method.
i
otherwise I'd have to implement a subject or something in the repo and notify the observers when the preference is changed... that's not what I had in mind for the overall architecture
aah, I'm understanding now
why exactly it didn't work
lol
you're right, the problem is not rx java's api
z
that’s not what I had in mind for the overall architecture
This is obviously off topic from your original question, but again… why not? Rx is short for “reactive”. Reactive means that code reacts to changes and external events – things like preferences changing. The advantage of reactive UI programming is that your UI will automatically update to reflect state changes. That said, maybe you’re not trying to build a reactive UI and only use RxJava as a concurrency library – and that’s fine too.
i
I am, but I'm wiring everything in the view models
could reconsider though
(almost everything, there are a few dependencies, like deep links broadcaster and similar that expose observables to the view models)
in this particular case I think I did it too because it was originally intended as an api service (so the repo just forwards to the api), so I just replicated the interface