Android SDK and "surprise" - almost twins. You may know by heart the 
development.android.com , but at the same time continue to tear your hair when you try to do something more abruptly than the form-button-progress bar.
This is the final, third, part of a series of articles on Android's Ditches. 
In fact, of course there should have been about two dozen of them, but I am too modest. At this time, I finally finish the trouble in the SDK, which I happened to encounter, as well as touch on the now popular technology 
ReactiveX .
In general, the Android SDK, RxJava, Cuvettes - let's go!

Previous parts:
Situation
Once I did a test task. It was boring, monotonous and ... old. Very old. 
PSD from the last century. Well, not the essence. Having finished all the main points, I began to read all the indents (agas, in handles, in a ruler, in the old fashioned way). Things went well until I discovered a nasty menu mismatch in the app and in the 
PSD . The icon was the same, but the 
padding is not the same. As an adventurer, I didn’t reduce the icon, but decided to use the 
MenuItem actionLayout property. Quickly adding a new 
layout with the parameters I needed and rechecking the indents of the icons on the emulator, I sent the solution and went into the sunset.
Situation
What was my surprise when the answer came (literally): "Editing does not work." By the way, I tested the application in the same way and this way and should not have missed something. The panic intensified and the laconic form of the answer from which it was not clear what exactly did not work ...
... fortunately, it did not take long to search. As it became clear from the title, 
onOptionsItemSelected () is simply ignored when setting a custom 
layout .
Since then, I clearly realized that with 
Android, jokes are bad and even changes in design can lead to changes in the behavior of the application. Well, as always, the 
solution :
workaround@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); final Menu m = menu; final MenuItem item = menu.findItem(R.id.your_menu_item); item.getActionView().setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onOptionsItemSelected(item); } }); return true; } 
 ')
Situation
Perhaps each of us at least once heard of 
MVC and its relatives. On the 
MVVM android is not yet built (lying, you can, but so far 
Beta ), but 
MVC and MVP are being used extensively. But how? Any android developer is aware that when you rotate the screen, the 
Activity and 
Fragment are completely destroyed (and with them a handful of nerves to boot). So how do you apply, for example, 
MVP and at the same time be able to rotate the screen without harming the 
presenter ?
Decision
And there are already 3 main solutions:
- “Use Fragment.setRetainInstance () everywhere and you will be happy,” or something newbies usually say. Unfortunately, this decision, though it saves at first, but destroys all plans, if necessary, to add a Presenter to the Activity . And it happens. Most often with the introduction of DualPane .
 
 And also setRetainInstance () has a bug that does not alleviate its benefit. But more on that later.
- Libraries, frameworks, etc., etc. Fortunately, there are quite a lot of them: Moxy (the “must read” article on a similar topic) , Mosby , Mortar , etc. Some of them at the same time will keep you nerves when trying to restore the so-called View State .
- Well, the approach is "crazy hands" - we create a Singleton , we give it the GetUniqueId () method (let it return AtomicInteger values with increment on call). We create a Presenter and save the previously received ID in the Bundle of the Activity / Fragment ', and the Presenter is stored inside Singleton with access by ID . Is done. Now your Presenter does not depend on the lifecycle (otherwise, it’s in Singleton ). Don't forget to just delete Presenters in onDestroy () !
3. TextView with a picture
And as usual, one is not a ditch, but advice.
What will you do if you need to do something like this?
If your answer is “PF! What problems? 
TextView and 
ImageView in 
LinearLayout or 
RelativeLayout ”- then this advice is for you. Oddly enough, 
TextView has a 
TextView.drawable {ANY_SIDE} property along with 
TextView.drawablePadding ! They do exactly what they are supposed to do and no nested 
layouts to you.
What different TextView.drawable {ANY_SIDE} looks like Honestly, I myself found out about this property relatively recently and accidentally, because it didn’t even occur to me to search 
TextView properties related to pictures.
Situation
If your father is 
John Taytor , and your mother is 
Sarah Connor , and you came from far 2013, then you still have a fresh feeling of hatred for the 
Fragments that you 
put in . Indeed, at that time it was quite difficult to cope with their “disobedience” ( 
tyts , 
tyts ) and the “code with 
embedded Fragments ” quickly turned into a “code with crutches”.
At that time I was just beginning to program and, after reading such horrors, I decided not to take the 
nested Fragments in my hands.
As time went on, I did not use 
Fragment's nesting , but for some reason all the news of this plan passed me ... And then, suddenly, I came across the news (sorry, I sowed a link) that 
Fragment'y now all 
Nested and life in general == fairy tale. And what to say - I believed! Created a project, dashed an example where 
Fragment's hash Presenters were converted to color (this would immediately determine if the 
retain worked), launched, turned the screen and ...
AND..?
And I spent the whole weekend searching for the reason why only the first level 
Fragments (those stored in the 
Activity itself) are saved. Naturally, the first thing I began to sin on was myself. I rummaged through all the code, starting from the painting code, ending with the eradication of 
MVP , studied the 
SDK sources, dug tons of posts on 
Nested Fragments (and there is such a cloud that even developers feel sorry for), reinstalled the emulator (!) And only by the end of the last weekend found 
THIS !
For those who are too lazy to read: 
Fragment.setRetainInstance () keeps 
Fragment from being destroyed with the help of the 
FragmentManager - that's all ok. However, for some reason, one of the developers took, and added the line 
mFragmentManager = null; , and only for 
Fragment's implementation - so the 
Activity was fine!
Why, why and how it happened - interesting questions that remain unanswered. This single-line bug already stretches 2.5 versions. In the above link ( 
for the lazy, it is the same ) describes the 
workaround on reflection . Unfortunately, for now this is the only way to solve the problem (well, except for the complete copying of the source code to my project, of course). The problem itself is described in more detail on the 
bug tracker .
ps I do not sell the time machine ┬┴┬┴┤ (・ _├┬┴┬┴
Perhaps I'll start with the simplest and most important.
When I first took on the 
Rx , I was completely unclear about the difference between these methods. From a logic point of view, 
subscribeOn () changes the 
Scheduler on which 
subscribe () is called. But ... from the point of view of another logic, 
Subscriber inherits the 
Observer , and what does the 
Observer do? 
Observe probably. And this is where 
cognitive dissonance occurred. Understandings did not introduce either 
google , or 
stackoverflow , or even 
official marbles . But of course, such knowledge is extremely important and it came about after a week or two of errors with 
Schedulers .
I often hear this question from my acquaintances and sometimes I meet in various forums, so here’s an explanation for those who are still going to be “reactive” or use these operators simply intuitively, without worrying about the consequences:
Code Observable.just(null) .doOnNext(v0id -> Log.i("TAG", "0"))  
 I suppose (from my own experience) that the most incomprehensible thing is that everywhere 
ReactiveX is moving forward with the slogan 
“Everything is a stream” . As a result, the novice expects that each operator affects only the operators following it, but not the entire stream at all. However, it is not. For example, 
startWith () affects the beginning of the stream, and 
finallyDo - at its end.
And as for names, having rummaged in 
Rx source codes, you find out that the data is generated not by the 
Observable class (suddenly, yes?), But by the 
OnSubscribe class. I think it is from here that the confusing name of the operator 
subscribeOn () .
By the way, I strongly advise beginners, and even experienced connoisseurs, to familiarize themselves with the 
logos for Frodo logging . Save yourself a lot of time, because debugging the 
Rx code is another problem.
Situation
Often it happens that the 
Rx code grows and you want to somehow reduce it. 
The method of calling methods in the form of chains is good, yes, but here it has zero reuse - you have to call all the same methods every time doing small things, etc. etc.
Faced with such a need, beginners begin to think in terms of OOP and create, if absolutely everything is bad, static-methods and wrap the beginning of the call chain into it. If time does not end with this approach, it will degenerate into 3-4 wrappers into one 
Observable .
The real code in one of the real products RxUtils.HandleErrors( RxUtils.FireGlobalEvents( RxUtils.SaveToCaches( Observable.defer(() -> storeApi.getAll(filter)).subscribeOn(Schedulers.io()), caches) , new StoreDataLoadedEvent() ) ).subscribe(storeDataObserver); 
 In the future, this will bring a lot of problems to those who just want to understand what the code is doing and to those who want to change something.
And now what?
Chain-methods are good because they are easy to read. I advise you as soon as possible to learn how 
to make your operators and transformers . It is easier than it seems. It is only important to understand that 
Operator works with a data unit (for example, one 
onNext () call at a time), and 
Transformer converts the 
Observable itself (here you can combine the usual 
map () / doOnNext (), etc. into one).
All finished with children's games. Let's go to the Tubes.
7. RxJava : Chaos in the implementation of Subscriptions
Situation
So, you are reactive! You tried, you liked it, you want more! You are already writing all the tests on 
Rx . You rewrite your home project on 
Rx . You teach your cat 
Rx . And now the time has come to create the Grail - to build the whole architecture on 
Rx . You are ready, you breathe often and languidly and ... start ... 
moooya preheelestWhat is it for me?
Unfortunately, the above is just about me. I was so impressed with the power of 
Rx that I decided to completely revise all of my approaches to writing architecture. You could say I tried to reinvent 
MVVM through 
MVP + Rx .
However, I assume the biggest newbie mistake - I decided that I understood 
Rx .
To understand it well, it is absolutely not enough to write a couple of 
Rx applications . As soon as a task appears more difficult than to link click and download photos, videos and test data from three different sources, then sudden problems like 
backpressure will manifest themselves. And when you decide that you know 
backpressure , you 
realize that you know nothing about the 
Producer (which even has no normal documentation) ... Something I digress (and at the end of the article it will be clear why).
In general, the essence of the problem is again in logic, which runs counter to what is in reality.
How does listening usually happen? That is, the data source stores a reference to the listener.
But what happens in Rx? (Carefully, pieces of code 
trash will go now)
observer.unsubscribe () after 500ms
Code Observable.interval(300, TimeUnit.MILLISECONDS).map(i -> "t1-" + i).subscribe(observer); l("interval-1"); Observable.interval(330, TimeUnit.MILLISECONDS).map(i -> "t2-" + i).subscribe(observer); l("interval-2"); Observable.timer(500, TimeUnit.MILLISECONDS).map(i -> "t3-" + i).subscribe(ignored -> observer.unsubscribe()); 
 Result interval-1 interval-2 t1-0 t2-0 
 I guess this is the most expected result. Yes, in our class 
Subscriber (also 
known as 
Observer ) stores references to data sources, and not vice versa, so everything calms down after the first unsubscribe (just to be on the safe 
side , I 
’m reminding you that 
unsubscribed is one of the end states in 
Rx that you can't get out of how to recreate anything and everything).
subscription1.unsubscribe () after 500ms
And now let's try to unsubscribe from 
Subscription , not from 
Subscriber . From a logical point of view, the 
subscription should bind the 
Observer and 
Observable as 1: 1 and allow you to selectively unsubscribe from something, but ...
Code Subscription subscription1 = Observable.interval(300, TimeUnit.MILLISECONDS).map(i -> "t1-" + i).subscribe(observer); l("interval-1"); Observable.interval(330, TimeUnit.MILLISECONDS).map(i -> "t2-" + i).subscribe(observer); l("interval-2"); Observable.timer(500, TimeUnit.MILLISECONDS).map(i -> "t3-" + i).subscribe(ignored -> subscription1.unsubscribe()); 
 Result interval-1 interval-2 t1-0 t2-0 
 ... suddenly the result is exactly the same. I learned this far from the very beginning of my acquaintance with 
Rx , although I used a similar approach for a long time thinking that it works. The fact is that 
Subscriber implements the 
Observer interface and ... 
Subscription . Those. that 
Subscription that we have is the same 
Observer ! Here is such a turn.
I think 
defer () is one of the most frequently used operators in 
Rx (somewhere on par with 
Observable.flatMap () ). Its task is to postpone the initialization of the 
Observable data until it is called 
subscribe () . Let's try:
Code Observable.defer(() -> Observable.just("s1")).subscribe(observer); l("just-1"); Observable.defer(() -> Observable.just("s2")).subscribe(observer); l("just-2"); observer.unsubscribe(); Observable.defer(() -> Observable.just("s3")).subscribe(observer); l("just-3"); 
 Result s1 just-1 s2 just-2 s3 just-3 
 "So what? Nothing unexpected, you say. "Probably" - I will answer.
But what if you are tired of writing 
Observable.just () ? In 
Rx, and there is an answer. A quick search in Google finds the 
Observable.fromCallable () method, which allows 
defer'it not 
Observable , but the usual lambda. We try:
Code Observable.fromCallable(() -> "z1").subscribe(observer); l("callable-1"); Observable.fromCallable(() -> "z2").subscribe(observer); l("callable-2"); observer.unsubscribe(); Observable.fromCallable(() -> "z3").subscribe(observer); l("callable-3"); 
 Result (ATTENTION! Remove children and hamsters from the screen) z1 callable-1 callable-2 callable-3 
 It would seem that a method that does the same thing only with other initial data, but such a difference. The most incomprehensible (if you think logically) as a result is that he is not 
z1-z2-callable ... (if you believe everything described up to this point), but 
z1-callable .... What's the matter?
The fact is that...
And now to the point. The fact is that many operators are written differently. Someone before the next 
onNext () checks 
Subscriber's subscription, someone checks it after emit, but until the end of 
onNext () , and someone before and after, etc. This brings some ... chaos to the expected result. But even this does not explain the behavior of 
Observable.fromCallable () .
Inside 
Rx there is a class 
SafeSubscriber . This is the class that is responsible for the main contract 
Rx (well, the one that says: “after 
onError (), there will be no more 
onNext () and there will be a reply, etc., etc.”). And whether it is necessary to use it ( 
SafeSubscriber ) in the operator or not is not stated anywhere. In general, 
Observable.fromCallable () calls the usual 
subscribe () , so 
SafeSubscriber is implicitly created and 
unsubscribe () occurs after the emith, but 
Observable.defer () calls 
unsafeSubscribe () , which does not cause 
unsubscribe () at the end. So actually (suddenly!) This is 
Observable.defer () bad, not 
Observable.fromCallable () .
8. RxJava : repeatWhen () instead of manual unsubscribe / subscribe
Situation
You need to update the data every X-seconds. Downloading new data, of course, cannot be done until old ones are loaded (this is possible due to lags, bugs and other mischief). What to do?
And in the answer 
everyone begins: 
Observable.interval () with 
Observable.throttle () or 
AtomicBoolean , and some even through manual 
unsubscribe () manage to make. In fact, everything is much simpler.
Decision
Sometimes it seems that 
Rx has operators for all occasions. So it is now. There is a 
repeatWhen () method that does everything for you - re-subscribes to the 
Observable at the specified interval:
Example use repeatWhen () Log.i("MY_TAG", "Loading data"); Observable.defer(() -> api.loadData())) .doOnNext(data -> view.setDataWithNotify(data)) .repeatWhen(completed -> completed.delay(7_777, TimeUnit.MILLISECONDS)) .subscribe( data -> Log.i("MY_TAG", "Data loaded"), e -> {}, v0id -> Log.i("MY_TAG", "Loading data"));  
 The only negative is that at first it is not entirely clear how this method works at all. But as usual, here is a 
good article on repeatWhen () / retryWhen () .
By the way, besides 
repeatWhen () there is also 
retryWhen () , which does the same, but for 
onError () . But unlike 
repeatWhen () , situations where 
retryWhen () can be useful 
are quite specific. In the case described above, it might be possible to add it. But in general, it is better to use 
Rx Plugins / Hooks and hang the global handler for the error of interest. This will not only re-subscribe to any 
Observable in case of an error, but also notify the user about it (I use something similar for a 
SocketTimeoutException for example).
Extra. RxJava : 16
Finally, that’s why I started writing about the Cuvettes. The problem I devoted to 2 weeks of my life and still have no idea what the ... magic is going on there ... But let's order.
Situation
You need to make an authorization screen, checking for incorrectly filled fields and issuing a special warning for every 3rd error.
The task itself is not difficult, and that is why I chose it as a “test site” for 
Rx . Thought, I will solve, I will look, as 
Rx behaves in business, other than simple data jump from the server.
So, the code was something like:
Login error code PublishSubject<String> wrongPasswordSubject = PublishSubject.create();  wrongPasswordSubject .compose(IndexingTransformer.Create()) .map(indexed -> String.format(((indexed.index % 3 == 0) ? "GREAT ERROR" : "Simple error") + " #%d : %s", indexed.index, indexed.value)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(message -> getView().setMessage(message)); 
 Code processing button [Sign In] private void setSignInAction() { getView().getSignInButtonObservable() .observeOn(AndroidSchedulers.mainThread()) .doOnNext((v) -> getView().setSigningInState())  
 Postpone claims to the 
Rx- style code - everything is bad, I know myself. The point is not that, and it was written a long time ago.
So, 
getView (). GetSignInButtonObservable () returns the 
Observable received from 
RxAndroid 'for clicking the 
[Sign In] button. It is 
hot-observable , i.e., it will never be able to be 
completed . Events start from it, pass through 
map () , in which authorization takes place and further along the chain. If an error occurs, the custom 
Operator will intercept the error and simply will not miss it further:
SuppressErrorOperator public final class SuppressErrorOperator<T> implements Observable.Operator<T, T> { final Action1<Throwable> errorHandler; public SuppressErrorOperator(Action1<Throwable> errorHandler) { this.errorHandler = errorHandler; } @Override public Subscriber<? super T> call(final Subscriber<? super T> subscriber) { return new Subscriber<T>(subscriber) { @Override public void onCompleted() { subscriber.onCompleted(); } @Override public void onError(Throwable e) { errorHandler.call(e);  
 So the question is. What's wrong with this code?
If they asked me about it, I would even now answer: “everything is OK”. Well, except that memory leaks, because nowhere is there a save 
Subscription . Yes, only 
onNext is overwritten in 
subscribe , but other methods will never be called. All right, working on.
Pain
Outset
And here the strangest begins. The code really works. However, I am a meticulous person and therefore I decided to press the authorization button ... many times. And, quite suddenly, I discovered that for some reason, after the 5th “GREAT ERROR”, the authorization progress bar (which was delivered via 
setSigningInState () ) did not appear (this function also turns off the 
[Sign In] button).
"Hmm" - I think. Rechecked the functions in 
Fragment 'e, responsible for the 
UI (all of a sudden there is something wrong inserted). I revised the 
auth () function, maybe I set the timeout for the tests. Not. Everything is good.
Then I decided that this is a 
race of threads . I started it again and checked it again ... Exactly 5 “GREAT ERROR” and again the stagnation of endless progress bar. And here I am tensed. Launched again, and then another and another. Exactly 5! Each time, exactly after the 5th “GREAT ERROR”, the button stops responding to pressing, the progress bar turns and silence.
“Okay” - I decided, “I will 
remove the setSigningInState () . You never know, 
Android loves to play with people. Suddenly, there was something in the 
SDK that broke and the whole thing was just that I couldn’t press the button again, and not that its handler didn’t work. ” Not. Did not help.
By this moment I was already very tense. In 
LogCat is empty, there were no errors, the application is running and has not hung. Just the handler is no longer processing.
Analysis
It turned out that the task itself had deceived me. I considered the number of "GREAT ERROR", but in fact it was necessary to count the number of button presses. Exactly 16. The number has changed, but the situation remains.
So, the code for the next attempt after getting rid of all unnecessary:
Code with logs in doOnNext () private void setSignInAction() { getView().getSignInButtonObservable() .observeOn(AndroidSchedulers.mainThread()) .doOnNext((v) -> l("1")) .observeOn(Schedulers.newThread()) .doOnNext((v) -> l("2")) .map(v -> { throw new RuntimeException(); }) .lift(new SuppressErrorOperator<>(throwable -> wrongPasswordSubject.onNext(throwable.getMessage()))) .doOnNext((v) -> l("3")) .observeOn(AndroidSchedulers.mainThread()) .doOnNext((v) -> l("4")) .subscribe(user -> runOnView(view -> view.setTextString("ON NEXT"))); } 
 And here the situation has become even stranger. From 1 to 15 clicks went right, the digits “1” and “2” were displayed, but for the 16th time the last line in the logs was ... “1”! It just did not reach the error generator!
"So maybe it's not at all in 
Exception ?!" - I thought. 
throw new RuntimeException() return null … , 4 (, 100 , … ).
2 3 , :
- 16
- Exception
- - doOnNext() «2», Exception
…
ReactiveX . 
RxJava , , wiki, , … « ».
, , : 
onBackpressureBuffer() . 
backpressure wiki RxJava' , , , .
, . 
backpressure , , . — 
zip() . 1 
, — 1 
, 
zip() . 
onBackpressureBuffer() — , , , 
zip() ( 
OutOfMemoryException , ).
, 
onBackpressureBuffer() ? , . 
[Sign In] only once a minute (well, you never know, what if I click The Flash and click too fast?). Of course it did not help.The final
, , , 
observeOn() . « ?» — . " ¯\_(ツ)_/¯ " — .
, 
onBackpressureBuffer() Observable . 
OnSubscribe -, 
Producer … . , 
Rx , , , — , — .
stackoverflow , .
2 , 
onBackpressureBuffer() ( , , , ?).
, , 
observeOn() Subscriber - 
Subscriber Exception' , ( 
Exception , , 16). 17 , 
observeOn() isUnsubscribed() , .. 
true , . ( ).
16 — 
Backpressure Buffer Android' . 
Java 128 , , . , 16 - , 5 — . 16 , 2+2=17.
, , — 
SuppressErrorOperator . , 
MissingBackpressureException . - . , — 
SuppressErrorOperator , 
MissingBackpressureException . Since , ( 16 
[Sign In] ).
Conclusion
. , Rx — Loader' . Netflix .
, Rx : . , , — . - . Rx — , . Rx- . (, 
Retrofit- ), Rx, , Subscription .. ( - View State Backpressure Producer. . ). , , .
, Rx, , : 
(Ctrl+F - 
Scan ), 
RxJava wiki github' ( - ) 
.
ps - , — , . , .
UPD : 
16 stackoverflow akarnokd ( 
RxJava , 
artemgapchenko ). , 
observeOn() decople' , 
backpressure buffer . Since 
Exception request() , «» , 
observeOn() , — 
16 . 
onBackpressureBuffer() , 
Long.MAX_VALUE . 
akarnokd' .