Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Loading in …3
×
1 of 35

MVVM and RxJava – the perfect mix

39

Share

Download to read offline

Slides for Droidcon Zagreb 2016 "MVVM and RxJava – the perfect mix" talk

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

MVVM and RxJava – the perfect mix

  1. 1. 1 MVVM and RxJava – the perfect mix Florina Muntenescu Droidcon Zagreb 2016
  2. 2. 2 What and who upday is
  3. 3. 3 When did we decide to go the RxJava & MVVM way?
  4. 4. 4 The old app When did we decide to go the RxJava & MVVM way?
  5. 5. 5 The old app When did we decide to go the RxJava & MVVM way? 99 little bugs in the code. 99 little bugs in the code. Take one down, patch it around. 127 little bugs in the code…
  6. 6. 6 From the old to the new When did we decide to go the RxJava & MVVM way?
  7. 7. 7 Crash course in RxJava
  8. 8. 8 Sum it up! Crash course in RxJava A1 0 A2 2 C1 3 combineLatest( (A1,A2) => A1+A2) 0 0 1 1
  9. 9. 9 What is MVVM and how do you apply it?
  10. 10. 10 Model-View-Presenter What is MVVM and how do you apply it? ModelView Presenter IView IPresenter 1 … 1
  11. 11. 11 Model-View-ViewModel What is MVVM and how do you apply it? DataModelView ViewModel 1 … *
  12. 12. 12 What is MVVM and how do you apply it?
  13. 13. 13 Model-View-ViewModel What is MVVM and how do you apply it? DataModelView ViewModel 1 … *
  14. 14. 14 Testing What is MVVM and how do you apply it?
  15. 15. 15 Model-View-ViewModel What is MVVM and how do you apply it? DataModel 1 … * View ViewModel 1 … * View ViewModel 1 … * View ViewModel 1 … * View ViewModel
  16. 16. 16 What is MVVM and how do you apply it? 1 … * Function View Function ViewModel1 … *Spreadsheet View Spreadsheet ViewModelObservable<String> getFunctionText()
  17. 17. 17 What is MVVM and how do you apply it? 1 … 1 Function View implements IFunctionView Function Presenter1 … 1Spreadsheet View Spreadsheet Presenter implements IFunctionView void textUpdated(String)
  18. 18. 18
  19. 19. 19 We made mistakes but we recovered!
  20. 20. 20 We made mistakes but we recovered!
  21. 21. 21 View We made mistakes but we recovered!
  22. 22. 22 ViewModel We made mistakes but we recovered!
  23. 23. 23 View We made mistakes but we recovered!
  24. 24. 24 We made mistakes but we recovered! What about Views that don’t have have lifecycle events?
  25. 25. 25 We made mistakes but we recovered! Views and subscriptions
  26. 26. 26 We made mistakes but we recovered! Views and subscriptions
  27. 27. 27
  28. 28. 28 RxJava – the good and the bad
  29. 29. 29 RxJava – the good and the bad RxJava vs Threads/AsyncTask/Event bus frameworks
  30. 30. 30 Stream composability FTW! RxJava – the good and the bad
  31. 31. 31 Split a string using a regular expression and append a new line to each item in the resulting list RxJava – the good and the bad “RxJava – the good and the bad” [“RxJavan”, “then”, “goodn”, ”andn”, “then”, ”badn”]
  32. 32. 32 RxJava – the good and the bad map(line -> line.trim() + NEW_LINE) toList() “RxJava“ … “the“ “good“ “RxJavan “ … “then“ “goodn“ ["RxJavan“, “then“, “goodn“ ...]
  33. 33. 33 Split a string using a regular expression and append a new line to each item in the resulting list RxJava – the good and the bad
  34. 34. 34
  35. 35. 3535 Simple MVVM example: https://github.com/florina-muntenescu/DroidconMVVM MVP vs MVVM example: https://github.com/florina-muntenescu/MVPvsMVVM Exclusive to Samsung

Editor's Notes

  • upday is an aggregated news content platform that offers both machine and human recommended content. Our app is preinstalled on the Samsung Galaxy S7 and S7 edge for customers in France, Germany, Poland and the UK.
    We are integrated on the -1 page of the home screen – one right swipe from the main home screen, opens our news service.
    The pre-installation brings with it millions of users but also a big responsibility: of building a stable, robust and easy to extend app that, on top of this, is also catchy and easy to use.

    That’s a challenge!

    I want to talk today about the turning point times in the development of the app. The ones where we were making the decisions that we knew will make us or break us.
  • 3 months before delivering the final build to Samsung for the preinstallation, our situation was the following: we were 8 devs, most of us quite new to the project, needing to work on a code base that was started by another team.
    Developers always complain about the guys that developed the code before them. We complained also.
    We had a sort of an MVC code, with the main action happening in the StreamFragment – a monster class and the heart of the app! This fragment pretty much contained 3 different screens and user flows, put together in one. The fragment was actually the one that was deciding what and how to display, and was even telling the database what to save.
  • This is pretty much how messy our code was. You could see magic numbers, lots of checks for Null (since this is the best way to avoid NullPointerExceptions, right?), these kind of if statements with lots of conditions, comments that didn’t actually say anything and not even the formatting wasn’t correct.

    Therefore, there shouldn’t be any surprise that fixing one bug was creating 999 other bugs.
  • At this point, the team was starting to use RxJava and MVVM here and there, in the new screens that needed to be created.

    It was then when we were told that we need to do a complete redesign of the app. In 3 months.
    To do new from old, with that StreamFragment… we decided to take the leap and instead of going through the hard pain of working on top of the existing code, to practically do most of the things from scratch using RxJava and MVVM as main concepts in our app.
    Of course, some logic was moved, but most of it was just re-written.
  • ReactiveX is an API that focuses on asynchronous composition and manipulation of streams of data.
    RxJava is the open-source implementation of ReactiveX in Java. The two main classes are Observable and Subscriber.
    In RxJava, an Observable is a class that emits a stream of data, and a Subscriber is a class that acts upon the emitted items. 
  • Let’s try to do an addition. Let’s say that we want to add whatever is in A1 with whatever it is in A2.
    That’s pretty easy, right? In our sum field we just say that we want there =sum(A1, A2)

    So, this means that we have a stream of events for A1 cell, a stream of events for A2 cell and our cell that contains the sum.

    Since at the beginning we don’t have anything in the cells, we consider that the value is 0.
    Whenever we have a new number in A1, our sum gets updated automatically.

    In terms of RxJava – A1 and A2 are called observables.
    And what we need to do is to combine the latest emission the 2 observables, creating a new one –C1.
    The combineLatest method is actually called an operator.
    The class that acts upon the emitted items, is called the subscriber. In this example, the subscriber will be the one that will connect the emissions of every element of C1 and connect it it to the text view on the screen.
  • Why did we decide to use MVVM? Let me tell you what MVVM is and you’ll understand.
    MVVM is a variation of Martin Fowler’s MVP.

  • The MVP pattern has 3 components:
    A view, that informs the presenter about the user actions
    The presenter that tells the view what to display, meaning that we have a 2 way communication between the View and the Presenter. There is one-to-one relationship between View and Presenter means one Presenter is mapped to only one View.
    The presenter works with the model to get and save data.
    View has a reference to Presenter but View does not have a reference to the Model.
  • Like MVP, MVVM abstracts a view’s state and behavior.
    But, if the Presentation Model abstracts a view independent from a specific user-interface platform, the MVVM pattern was created by Microsoft to simplify the event driven programming of user interfaces.
    The ViewModel exposes streams of events that the views can bind to. Also, the views are notifying the ViewModel about different actions.
    Therefore, the MVVM pattern supports two-way data binding between the View and ViewModel and there is many-to-one relationship between View and ViewModel. View has a reference to ViewModel but ViewModel has no information about the View.
    What we are doing is more DataModel – View- ViewModel, because the DataModel is the one that abstracts the data source.
    The event driven part is done using RxJava’s Observables.
  • Things are easier to understand with examples.
    Let’s take a simple “Hello World” and do it with MVVM.
    So, our app has a simple activity that contains a text view. The text view needs to display a text that comes from a model.

    Let’s take each component in a row and see what their role is and how we can implement our pattern.
  • DataModel – is the one that provides the greeting.
    Exposes the data that is easily consumable through event streams (in our case RxJava’s Observables). Composes data from multiple sources (BE requests, database) and exposes them to whoever needs it. It’s easy to unit test.

    ViewModel – in our case, it just exposes the greeting received from the data model.
    Is a model for the view of the app, an abstraction of the view. It exposes data relevant to the view and behaviors for the view. The VM is completely separated from the UI therefore straightforward to unit test.

    View
    Is the actual user interface in the app – the activity that contains the text view that we need to set. View’s role is just to react on the events from the ViewModel. The View binds and un-binds from the event sources on onResume and onPause.
    In the bind method, we’re just saying that every time the view model emits a new greeting, it should be set as a text for our text view. Like this, we bind the data emitted by the view model with the text view.

    MVVM combines the advantages of separation of concerns, provided by MVP, while leveraging the advantages of data bindings. Therefore, the result is a pattern where the model drives as much as the operations as possible, minimizing the logic in the view.

    Since the view is just a consumer of the model, then it’s easy to just replace different UI elements, without needing to change any other layer. Because the ViewModel shouldn’t change when changing the view, the regression testing comes for free, which helps reduce the cost of maintaining the app over time.  

    Let’s see more about testing!

  • So, how do we test our Hello World?

    With Mockito we just mock the data model and we pass the mocked object to the constructor of the view model.

    To check if indeed the view model emits the correct string, we’re just saying that when getGreeting is called, an observable containing the string that we defined needs to be returned.
    We subscribe then to the greeting and we expect that once subscribed, this will emit also the greeting that we previously defined.

    So, since all of the logic is hold in the ViewModel, and we can mock the data model, then our class is easy to be tested.

    With MVVM you have to look at things differently - Just consider the views and the unit tests as 2 different types of ViewModel consumers.
    If you want to do TDD – then this is the right place.


    The testability of ViewModel classes help designing interfaces. When you need to decide whether something needs to be in the View or in the ViewModel, imagine that you want to write a unit test to consume the VM. If you can write unit tests for the ViewModel without creating any UI objects, then you have your answer.
  • So, until now you might say that this doesn’t sound so different from MVP but this small difference – the many-to-one relationship, that fact that the ViewModel exposes streams of data, not knowing (and not caring) who consumes it, makes a big difference. In the end, the consumer should know about the producer, but not the other way around.

    If the MVVM pattern can seem an overhead in small apps, its power is visible in bigger ones.
    Let’s consider that you have complex views, with components that depend on one another and need to react on different changes.
    The separation of concerns and the single responsibility principles tell you that you need to split them, create ViewModels for all of them.
    Then just allow the view models to expose the right events, for other view models to consume.
    Not having the ViewModel dependent on a view, like the Presenter is, also allows them to be easily injected and makes the ViewModel independent from the state of the view.

    Having the view model exposing streams of data leads also to a higher degree of testablity and a better control of working threads.
  • SpreadsheetViewModel

    Because the function edit text is a complex one, with several functionalities, then it requires its own ViewModel - > FunctionViewModel

    Whenever we type something in the edit text, the selected cell in the spreadsheet needs to be updated. Therefore, the FunctionViewModel can expose a method like
    Observable<String> functionText().

    The SpreadsheetViewModel can use this data and put it in the cell.
    So, the SVM and the FunctionView are consumers of the functionText()

    How would this be implemented with MVP?

    You would have a SpreadsheetPresenter and a FunctionPresenter, that uses a FunctionView, that implements Iview.
    Since the SpreadsheetPresenter needs to be notified of changes in the functionText, it would need to implement Iview and the FunctionPresenter would need to support a list of Iviews.
    SO, the SpreadsheetPresenter is a presenter and a view in the same time.
  • How would this be implemented with MVP?

    You would have a SpreadsheetPresenter and a FunctionPresenter, that uses a FunctionView, that implements Iview.
    Since the SpreadsheetPresenter needs to be notified of changes in the functionText, it would need to implement Iview and the FunctionPresenter would need to support a list of Iviews.
    So, the SpreadsheetPresenter is a presenter and a view in the same time.
  • Summary:

    Separation of concerns
    Testability
    Binding view model’s data emissions to components of the view
  • Everything sounds good in theory and for small apps but do this actually works in the real world?
    I want to tell you about some mistakes done and I’m going to try to simplify them using our Hello world example.
  • Starting from our “Hello World!”, our product owner, decided that he wants to display also the city.
    For our UI design patterns, this means nothing, since the greeting would come from the DataModel.
    But, then our PO decides that if the greeting contains the word “Zagreb” then he wants an image to be displayed. And this change needed to be done for tonight’s release.
  • What we did first was to say, in the view, that if the greeting contains the word ”Zagreb” then just set an image.

    The app was doing what it needed and got released, our PO was happy.
    But we weren’t.
  • We don’t like UI tests, but we love unit tests.
    The view should not do logic decisions, the view model should.
    So we created a getImage stream, that just emits something when the greeting contains what it should.

    The tests are simple and they allow us to test both the positive and the negative case.

    Similar to the tests for the greeting, we mocked the data returned by the data model – in the first test case, but returning a string that contains the word Zagreb. Therefore, our expectation was that, when subscribed to the image emissions, then we indeed get the correct drawable.

    In our test case, we create a greeting that does not contain the word zagreb, and, since we wanted this not to emit anything, we just assert that our subscriber has not indeed emitted any values.
  • In our View, things are equally simple. On bind, we just subscribe on the image events and we just set the image, when the event arrives.

    Now, imagine this mistake – of putting too much logic in the view – in a bigger, complex app. It wasn’t so pretty.

    But then we took a step back, we realized that ….
    … this is not how things should work, that good programming requires principles like loose coupling, separation of concerns and single responsibility. Things that we knew but which could have been better applied.

    So we moved the logic out from the view and in the view model.
    There, we refined the logic even more, keeping classes with only one (or at least few) responsibilities but making everything unit testable.
  • I was saying earlier that we bind and unbind from the observables on onResume and onPause.
    But what do we do when we don’t have an Activity or a Fragment acting as a View in our MVVM pattern?
    What if we actually have a View? So no onResume and onPause methods.






  • Well usually, we have something like this…

    But the problem here is that the subscription is preserved unncesarelly and can lead to memory leaks.


  • What’s the solution?
    Call unbind on onDetachedFromWindow



  • We learned 2 important things:

    Keep all logic away from the View Make sure you unbind from all subscriptions
  • I keep on mentioning here RxJava but, if MVVM pattern was created by Microsoft to implement user interfaces using event driven programming then, is RxJava really the best option?
    Let’s see what are the advantages of Rx compared to other possibilities but also, what are the disadvantages.
  • Think how you would do this with Threads/AsyncTasks.
    RxJava allows better handling of Activity/Fragment lifecycle, caching on rotation, composing multiple streams, error handling and testability

    How would you do this with event bus frameworks?
    Compared to Event Bus frameworks RxJava offers readability, ease of debugging, less boilerplate, capability of filtering the results and manipulate the data.
  • Observables help provide simple, yet asynchronous APIs but they really shine with their composability aspects.

    Remember our excel example from the RxJava crash course? Let’s see how this would look when actually implemented.
    We would have a method - get sum, that would receive the A1 and A2 observables as parameters and it would combine the latest emissions of the 2, using a function. In our case, that function is a sum.
    Combining 2 threads or events from 2 different sources using event bus framework, would require a lot of boiler plate. But like this, the code is simple and easy to read.

    RxJava’s operators are elements that make iterative operations look nice and easy to understand, when done in a functional way.
    And, most of all, in general, RxJava code is testable!

    All of this sounds amazing! RxJava is magic! But are there any dark sides of this magic?
  • Using operators, transformers and other functionalities offered by Rx require quite a high learning curve.
    But, once developers understand how these work, they tend to use it for everything.
    I want to show you an example from our own production code – the Rx way. Then I will show you how it looks without Rx and we’ll try to find out whether Rx was really the right solution.

    The task is simple: split a string using a regular expression and then append a new line to each item in the resulting list.
  • The developer that implemented this is really familiar with Rx so let’s see what he did here:
    It converts the list resulted from splitting of the text to an Observable. So this means that every item of the split will be emissions of our observable. Every string emitted will be trimmed and then a new line will be added.
    Since we need a list to be retuned, the operator ”ToList” is used to gather all the emissions in a single list. Then, since we don’t need an observable of list but the actual list, this means that we don’t need this entire operation to happen asynchronous so we are using “toBlocking” to make it synchronous. “single” is the operator that returns us the list.

    Given that it took me 5 minutes to explain 6 lines of code, it’s easy to see that, especially for beginners, RxJava code can seem hard to read.
  • Let’s see how we can do this iteratively: we just get an array of the text spit, we iterate through it and create a new list containing the words trimmed and with a new line added. Well.. That sounded simple.

    The only advantage that Rx has in this case, it’s just that it’s prettier. Both methods are actually synchronous and even more, Rx way is slower in this case. In general for simple operations like this, the declerative way is slower.

    When not implemented properly, RxJava brings with it sometimes racing issue or in general, possible threading problems.
    But don’t let yourself be scared by these possible issues. A lot of them have already been addressed and solved and most of them, just require reading and understanding of the API.
  • Title: RxJava – the good and the bad

    Doing async operations is easy in Rx
    … After you’re over the initial steep learning curve
  • The leap took when we did the redesign allowed us to establish a very good backbone of the app and provided us with a great overall strategy in terms of architecting our app.
    We learned a lot in these months, sometimes the hard way, but now we are in a state where the app is quite separate, responsibilities of the classes are pretty well determined and adding multiple features in the same time or fixing issues can be done with minimum interference. No merge conflicts makes developers happy.
  • ×