But that whole start / stop / interrupt / post on ...
# coroutines
p
But that whole start / stop / interrupt / post on UIThread logic is messy
e
paulwoitaschek: What class actually uses
BookAdder.scannerActive
obervable value?
p
A presenter that shows a loading state based on that
e
What's the idea behind
stopScanner
flag? I cannot follow the logic. There is only one place where it is set to
true
, but then immediately to
false
again...
p
That's what I mean with messy logic 😄
The executor is a
singleThreadExecutor
Each of the task performing methods calls before and after each heavy operation:
Copy code
private fun throwIfStopRequested() {
    if (stopScanner) {
      throw InterruptedException("Interruption requested")
    }
  }
After that
InterruptedException
was caught it sets the flag to false because the single thread from the executor completed
e
I'm not an Rx expert, but I think there are some ready-to-use Android schedulers out there, so that you can do
observeOn(AndroidSchedulers.mainThread())
without the need to work with loopers explicity.
As for stopScanner logic, you might be able to save a bit of code with coroutines, because there is a ready-to-use Job object. You replace
val executor = Executors.newSingleThreadExecutor()
with
val context = newSingleThreadContext()
and replace
executor.execute { ... }
with
launch(context) { ... }
. You get the job, that you can cancel, so now you'll need to keep a reference to the last job:
Copy code
fun scanForFiles(interrupting: Boolean) {
    if (job?.isActive != true || interrupting) {
        job?.cancel()
        job = launch(Context) {
          ...
       }
}
Instead of
throwIfStopRequested
you can just use
yield
. Saves you a few lines, but all in all it does not get really much different.
p
Thanks, I'll give that a try
About the
observeOn
thing: Often times its easier to just stay on the ui thread
See

https://www.youtube.com/watch?v=va1d4MqLUGYâ–¾

Btw is it possible to move from an infinite stream like a Rx subject to a coroutine?
e
Coroutine is not a stream. Coroutines replace threads, but they don't replace your data models. Here you are using Rx Observable<Boolean> as a model of your state, so that your view can present it. I bet you can use something else, but that other thing is definitely not going to be a coroutine, but some kind of data structure.
p
Still trying to understsand where that hammer fits. When doing chained transformations it can greatly simplify a large map, flatMap, filter, ... Chain. But once some stream based comes into play I can't apply it any longer
e
With coroutines you can use something much simpler than Rx to model your state. For example, in JavaFx they have observable (and bindable) properties for that. Android UI architecture is quite primitive and does not offer anything like that out of the box, so you have to rely on hand-written or 3rd party libs for your models. If rx Observable works well for your view-model interaction, then I don't see a reason to replace it.
p
Then I guess I'm fine with the way I do it now. I find that sometimes the transition is really nice. Especially when I have one shot events like: user clicks a button, I merge user input plus 3 rxSingles to a dto object and upload that
Then the code is plain simple because you just call view.showLoading, .... Await, upload().Await, view.showSuccess