Observable transformers made of Subjects - android

I am currently implementing a pattern that has a view-viewmodel circular dependency. Though its really not dependency because they don't know about each other, all they know is that there is a stream of events and a stream of states. I came up with an idea of making the viewModel implement a function called toTransformer() which returns an ObservableTransformer that's composed of two subjects, an event subject and a state subject.
private val eventStream: PublishSubject<MainEvent> = PublishSubject.create()
private val stateSink: BehaviorSubject<MainState> = BehaviorSubject.create()
...
fun asTransformer(): ObservableTransformer<MainEvent, MainState> =
ObservableTransformer {
it.subscribe { eventStream.onNext(it) }
stateSink
}
And is used like this
view.events().compose(viewModel.asTransformer()).subscribe { view.render(it) }
Questions
Is it okay to do this?
What could go wrong with this implementation.
Will the inner subscription be disposed if the subscription is disposed?
Can this be improved to a better form?
Edit
This is how event and state relates.
eventStream.map { it.toAction() }
.compose(actionToResult())
.scan (MainState.initial(), reducer())
.subscribe {
stateSink.onNext(it)
}

I don't know if you based it off of this, but Jake Wharton has a great presentation on this kind of architecture.
Is it okay to do this?
In general, sure.
What could go wrong with this implementation.
One thing you probably want to be careful of is that you essentially have one big event loop. If your event loop dies, the UI will be non-responsive. Correct error handling is even more important than before. I'm sure your code snippets above are a simplified version of what you really have, but consider that without an error handling block, failures in your inner subscription will bubble up to your outer subscription which will itself fail. At this point, there will be no active subscriptions to UI events.
Will the inner subscription be disposed if the subscription is disposed?
No. It's not in the same chain.
Can this be improved to a better form?
Especially in consideration of the previous answer, you may want to get rid of the inner subscription so that it's all one chain. An easy way is to use flatMap instead of subscribing.

Related

Where to do Arrow.io IO.runUnsafeSync() ? ViewModel or Activity/Fragment?

I'm trying to learn the Arrow library and improve my functional programming by transitioning some of my Android Kotlin code from more imperative style to functional style. I've been doing a type of MVI programming in the application to make testing simpler.
"Traditional" Method
ViewModel
My view model has a LiveData of the view's state plus a public method to pass user interactions from the view to the viewmodel so the view model can update state in whatever way is appropriate.
class MyViewModel: ViewModel() {
val state = MutableLiveData(MyViewState()) // MyViewState is a data class with relevant data
fun instruct(intent: MyIntent) { // MyIntent is a sealed class of data classes representing user interactions
return when(intent) {
is FirstIntent -> return viewModelScope.launch(Dispatchers.IO) {
val result = myRoomRepository.suspendFunctionManipulatingDatabase(intent.myVal)
updateStateWithResult(result)
}.run { Unit }
is SecondIntent -> return updateStateWithResult(intent.myVal)
}
}
}
Activity
The Activity subscribes to the LiveData and, on changes to state, it runs a render function using the state. The activity also passes user interactions to the view model as intents (not to be confused with Android's Intent class).
class MyActivity: AppCompatActivity() {
private val viewModel = MyViewModel()
override fun onCreateView() {
viewModel.state.observe(this, Observer { render(it) })
myWidget.onClickObserver = {
viewModel.instruct(someIntent)
}
}
private fun render(state: MyViewState) { /* update view with state */ }
}
Arrow.IO Functional Programming
I'm having trouble finding examples that aren't way over my head using Arrow's IO monad to make impure functions with side effects obvious and unit-testable.
View Model
So far I have turned my view model into:
class MyViewModel: ViewModel() {
// ...
fun instruct(intent: MyIntent): IO<Unit> {
return when(intent) {
is FirstIntent -> IO.fx {
val (result) = effect { myRoomRepository.suspendFunctionManipulatingDatabase(intent.myVal) }
updateStateWithResult(result)
}
is SecondIntent -> IO { updateStateWithResult(intent.myVal) }
}
}
}
I do not know how I am supposed to make this IO stuff run in Dispatcher.IO like I've been doing with viewModelScope.launch. I can't find an example for how to do this with Arrow. The ones that make API calls all seem to be something other than Android apps, so there is no guidance about Android UI vs IO threads.
View model unit test
Now, because one benefit I'm seeing to this is that when I write my view model's unit tests, I can have a test. If I mock the repository in order to check whether suspendFunctionManipulatingDatabase is called with the expected parameter.
#Test
fun myTest() {
val result: IO<Unit> = viewModel.instruct(someIntent)
result.unsafeRunSync()
// verify suspendFunctionManipulatingDatabase argument was as expected
}
Activity
I do not know how to incorporate the above into my Activity.
class MyActivity: AppCompatActivity() {
private val viewModel = MyViewModel()
override fun onCreateView() {
viewModel.state.observe(this, Observer { render(it) })
myWidget.onClickObserver = {
viewModel.instruct(someIntent).unsafeRunSync() // Is this how I should do it?
}
}
// ...
}
My understanding is anything in an IO block does not run right away (i.e., it's lazy). You have to call attempt() or unsafeRunSync() to get the contents to be evaluated.
Calling viewModel.instruct from Activity means I need to create some scope and invoke in Dispatchers.IO right? Is this Bad(TM)? I was able to confine coroutines completely to the view model using the "traditional" method.
Where do I incorporate Dispatchers.IO to replicate what I did with viewModelScope.launch(Dispatchers.IO)?
Is this the way you're supposed to structure a unit test when using Arrow's IO?
That's a really good post to read indeed. I'd also recommend digging into this sample app I wrote that is using ArrowFx also.
https://github.com/JorgeCastilloPrz/ArrowAndroidSamples
Note how we build the complete program using fx and returning Kind at all levels in our architecture. That makes the code polymorphic to the type F, so you can run it using different runtime data types for F at will, depending on the environment. In this case we end up running it using IO at the edges. That's the activity in this case, but could also be the application class or a fragment. Think about this as what'd be the entry points to your apps. If we were talking about jvm programs the equivalent would be main(). This is just an example of how to write polymorphic programs, but you could use IO.fx instead and return IO everywhere, if you want to stay simpler.
Note how we use continueOn() in the data source inside the fx block to leave and come back to the main thread. Coroutine context changes are explicit in ArrowFx, so the computation jumps to the passed thread right after the continueOn until you deliberately switch again to a different one. That intentionally makes thread changes explicit.
You could inject those dispatchers to use different ones in tests. Hopefully I can provide examples of this soon in the repo, but you can probably imagine how this would look.
For the syntax on how to write tests note that your program will return Kind (if you go polymorphic) or IO, so you would unsafeRunSync it from tests (vs unsafeRunAsync or unsafeRunAsyncCancellable in production code since Android needs it to be asynchronous). That is because we want our test to be synchronous and also blocking (for the latter we need to inject the proper dispatchers).
Current caveats: The solution proposed in the repo still doesn't care of cancellation, lifecycle or surviving config changes. That's something I'd like to address soon. Using ViewModels with a hybrid style might have a chance. This is Android so I'd not fear hybrid styles if that brings better productivity. Another alternative I've got in mind would maybe be something a bit more functional. ViewModels end up retaining themselves using the retain config state existing APIs under the hood by using the ViewModelStore. That ultimately sounds like a simple cache that is definitely a side effect and could be implemented wrapped into IO. I want to give a thought to this.
I would definitely also recommend reading the complete ArrowFx docs for better understanding: https://arrow-kt.io/docs/fx/ I think it would be helpful.
For more thoughts on approaches using Functional Programming and Arrow to Android you can take a look to my blog https://jorgecastillo.dev/ my plan is to write deep content around this starting 2020, since there's a lot of people interested.
In the other hand, you can find me or any other Arrow team maintainers in the Kotlinlang JetBrains Slack, where we could have more detailed conversations or try to resolve any doubts you can have https://kotlinlang.slack.com/
As a final clarification: Functional Programming is just a paradigm that resolves generic concerns like asynchrony, threading, concurrency, dependency injection, error handling, etc. Those problems can be found on any program, regardless of the platform. Even within an Android app. That is why FP is an option as valid for mobile as any other one, but we are still into explorations to provide the best APIs to fulfill the usual Android needs in a more ergonomic way. We are in the process of exploration in this sense, and 2020 is going to be a very promising year.
Hopefully this helped! Your thoughts seem to be well aligned with how things should work in this approach overall.

Is it possible to implement an operator like delay but that also delays errors?

I'm trying for some time now to implement an extension function (just becuse it's easier to me) that is capable of delaying both normal item emissions and errors. The existing delay operators only delays normal item emissions, errors are delivered ASAP.
For context, I'm trying to immitate an Android LiveData's behavior (kinda). LiveDatas are a observable pattern implementation that is lifecycle aware. Their observers are only notified if they are in a state where they can process that emission. If they are not ready, the emission is cached in the livedata and delivered as soon as they become ready.
I created a BehaviourSubject that emits the state of my Activities and Fragments when it changes. With that I created a delay operator like this:
fun <T> Flowable<T>.delayUntilActive(): Flowable<T> = delay { lifecycleSubject.toFlowable(BackpressureStrategy.LATEST).filter { it.isActive } }
and then use it like this
myUseCase.getFlowable(Unit)
.map { it.map { it.toDisplayModel() } }
.delayUntilActive()
.subscribe({
view.displaySomethings(
}, { }).addTo(disposables)
So even if myUseCase emits when the view is not ready to display somethings, the emission won't reach onNext() until the view does become ready. The problem is that I also want the view to displayError() when onError is triggered, but that too is lifecycle sensitive. If the view isn't ready, the app will crash.
So I'm looking for a way to delay both emissions and errors (onComplete would be good too). Is this possible?
I tried some things with zip, onErrorReturn, delay inside delay, but nothing seemed right. I'd be equally unimpressed if this had a really easy solution I'm overlooking, or is impossible. Any ideas are welcome.
Bonus: any better way to do that for Single and Completable too? currently I'm just converting them to flowable.
Thanks in advance!
You can handle the error via onErrorResumeNext, then taking the same error and delaying it via delaySubscription until your desired signal to emit said error happens:
source
.onErrorResumeNext({ error ->
Observable.error(error)
.delaySubscription(lifecycleSubject.filter { it.Active } )
})

Can we use LiveData without loosing any value?

I would like to use a LiveData for handling kind of notifications, as it is already lifecycle aware, between a custom view and its wrapping fragment. But it seems that a LiveData may loose values : it will only update to its most recent state and also won't fire values during inactive state of its observers.
I've looked at the SingleLiveEvent purpose from Google code samples, but that solution does not seems to be battle tested yet, and the ticket is still open with recent tries to improve the solution.
So I am looking for a simple way to get notified about events, and at the same time not being worried about Lifecycles (that was why I went for LiveData as a first solution), and that could handle multiple observers.
Is there an existing solution for that ? If I try to implement it, it is sure that I will land into at least an anti-pattern.
One easy way (perhaps too easy) is to use callbacks : but the problem is that I need this feature for several callbacks in my component, leading me in a poor architecture. And also, I want a subscribe system, meaning that there could be more than one observer.
One other way, could be to use RxJava and tranform it into a LiveData, with LiveDataReactiveStreams.fromPublisher() : but now the question is whether I will get all values or only the last one. That's the closest solution I could deal with.
As an interesting alternative there could be AutoDispose or RxLifecycle. And an interesting resource I've found : Blog post on LiveData
What are your thoughts, suggestions ?
Also, please notice that I need this communication from a component wrapped into a Fragment (ChessBoard) toward another Fragment (ChessHistory). So they are both lifecycle aware.
It is not ideal, but this does the trick for me:
/**
* This LiveData will deliver values even when they are
* posted very quickly one after another.
*/
class ValueKeeperLiveData<T> : MutableLiveData<T>() {
private val queuedValues: Queue<T> = LinkedList<T>()
#Synchronized
override fun postValue(value: T) {
// We queue the value to ensure it is delivered
// even if several ones are posted right after.
// Then we call the base, which will eventually
// call setValue().
queuedValues.offer(value)
super.postValue(value)
}
#MainThread
#Synchronized
override fun setValue(value: T) {
// We first try to remove the value from the queue just
// in case this line was reached from postValue(),
// otherwise we will have it duplicated in the queue.
queuedValues.remove(value)
// We queue the new value and finally deliver the
// entire queue of values to the observers.
queuedValues.offer(value)
while (!queuedValues.isEmpty())
super.setValue(queuedValues.poll())
}
}
The main problem with this solution is that if the observers are inactive at the time the values are delivered via super.setValue(), then the values will be lost regardless. However, it solves the issue of losing values when several new ones are posted very quickly – which, in my opinion, is usually a bigger problem than losing values because your observer is inactive. After all, you can always do myLiveData.observeForever() from a non-lifecycle-aware object in order to receive all notifications.
Not sure this will be enough for you, but I hope it can help you or give you some ideas about how to implement your own approach.

Naming convention for methods returning RxJava's Completable

I have and Android app with the view class (Fragment, Activity) observing its ViewModel.
The ViewModel exposes methods such as getUserName which returns Observable<String>. Although maybe there is a possibility to find a better name (maybe observeUserName), I'm happy with the current one - it is quite explanatory.
However, here starts the hard part: ViewModel also can tell the view to perform some operation - for example close itself, pop backstack etc. For this case ViewModel defines following method (and corresponging Subject):
class ViewModel {
// other methods, fields
// ViewModel can call returnToPreviousScreen.onComplete()
CompletableSubject returnToPreviousScreen = CompletableSubject.create();
Completable returnToPreviousScreen() { return returnToPreviousScreen; }
}
In my opinion, the method's name is terrible. Hovewer I can not find anything better. Something like observeWhenToReturnToPreviousScreen is maybe more explanatory but hard to read.
So, are there any recommendations or maybe commonly used practices for naming such methods?
There's no universal answer to the naming problem, so the only thing you can get are opinions.
Rule of thumb
My approach to naming in rx-java usually looks at two things:
Does it express a "stream" of emitted events (usually with a plural form of a noun)?
Does it work well with other parts of rx java methods chain, and especially the subscribe method?
Both of the above can be usually simplified to trying to put the name of the method in this sentence:
This code subscribes to {name_of_the_method}.
Examples
A) getUserName
This code subscribes to getUserName.
👎 The sentence does not really make sense because getUserName does not express the stream. Quite on the contrary, it suggests that there is one value that you can get.
getUserName().subscribe()
B) observeUserName
This code subscribes to observeUserName.
👎 Although the method kind-of expresses the stream of events, it does not work well with subscribe. Method exposing the Observable is not a place for information about observing. The consumer of the method will be observing what that method returns.
observeUserName().subscribe()
C) userNames
This code subscribes to userNames.
👎👍 This might work in some cases. It nicely expresses a stream of userName items being emitted and works well with subscribe. It really depends on a particular scenario, because it suggests that you can expect multiple userNames while you really want to observe how a single userName changes.
userNames().subscribe()
C) userNameChanges
This code subscribes to userNameChanges.
👍 This method nicely expresses that there is a stream of items ("change" events) and it works well with subscribe method.
userNameChanges().subscribe()
Return to previous screen
As far as your returnToPreviousScreen case goes, I think I would end up using something like:
This code subscribes to returnRequests().
or
This code subscribes to previousScreenRequests().
or even a singular form as there can only be one event emitted in the stream:
This code subscribes to previousScreenRequest().
(not a topic of a question but I think I would use a Single<Unit> rather than Completable, to express a singular event emission rather than a completion... but maybe that's just me).

Why should one consider using AndroidObservables in RxJava

As i understand AndroidObservable helps ensure that :
a Subscriber always observes on the main thread
when a fragment/activity is detached/stopped, then the observation stops immediately, and framework related components (like ui textviews etc.) are not updated.
However, in order to ensure that the context is released (preventing leakage), most examples I see typically say that you have to anyway do an .unsubscribe onDestroyView/onDestroy, which essentially halts the subscription, and prevents the subscriber from receiving these updates anyway.
So my question is:
Is there any other advantage to using AndroidObservables, if i manually indicate that the subscription should happen on the main thread, by way of .observeOn(AndroidSchedulers.mainThread() ?
Is there any difference in the below two approaches?
_subscription1 = AndroidObservable.bindFragment(MyFragment.this, myCustomAwesomeObservable()) //
.subscribeOn(Schedulers.io()) //
.subscribe(...);
_subscription2 = myCustomAwesomeObservable()
.subscribeOn(Schedulers.io()) //
.observeOn(AndroidSchedulers.mainThread()) //
.subscribe(...);
#Override
public void onDestroyView() {
_subscription1.unsubscribe();
_subscription2.unsubscribe();
super.onDestroyView();
}
You are right. What AndroidObservable.bindFragment currently does is:
This helper will schedule the given sequence to be observed on the main UI thread and ensure that no notifications will be forwarded to the activity in case it is scheduled to finish.
-- part of the source code comment
So, it does not really make a difference which of the implementations you use.
But, still it's a good idea to use the AndroidObservable as additional functionality could be added in the future.
It doesn't exist anymore since 1.0 release of RxAndroid. I guess you could say it's deprecated or discontinued. I don't think it's a good idea to use this anymore.

Categories

Resources