Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to use MVVM pattern in Android (Droidcon Kr...

How to use MVVM pattern in Android (Droidcon Krakow 2014)

I would like to show how to use Model-View-ViewModel (MVVM) design pattern on the Android platform. Using this approach UI code is easier to read, test and maintain.

I will show how it can help to:
• remove lots of unnecessary code
• not write boilerplate code any more
• turn Android unit tests running for ages into pure POJO PresentationModels with normal JUnit tests

I will show RoboBinding framework which helps to achieve this goals and how to configure gradle build script to use it.

More information about this talks is available here.

Radek Piekarz

December 04, 2014
Tweet

More Decks by Radek Piekarz

Other Decks in Programming

Transcript

  1. Butterknife public class MyActivity extends Activity { @InjectView(R.id.button) Button button;

    //…... @OnClick(R.id.button) void onButtonClicked() { //change the world //or maybe change the UI } // }
  2. Android Annotations @EActivity(R.layout.main_activity) public class MyActivity extends Activity { @ViewById(R.id.button)

    Button button; @Click(R.id.button) public void onButtonClicked() { //change the world //or maybe change the UI } }
  3. Model View Presenter • The model is an interface defining

    the data to be displayed • The view is a passive interface that displays data (the model) and routes user commands (events) to the presenter to act upon that data. • The presenter acts upon the model and the view. It retrieves data from repositories (the model), and formats it for display in the view.
  4. Model View Presenter on Android #1 public interface MyView {

    void hideLoading(); void showLoading(); void renderItems(final Collection<Item> items); boolean isReady(); boolean isAlreadyLoaded(); }
  5. Model View Presenter on Android #2 public class MyViewPresenter extends

    Presenter { private MyView view; public void setView(MyView view) { //checking if view is not null etc... this.view = view; } @Override public void initialize() { if(view.isAlreadyLoaded()) { view.showLoading(); } }
  6. Model-View-ViewModel • The Model, which provides a view-independent representation of

    your business entities. • The View class which is the user interface. It displays information to the user and fires events in response to user interactions. • The ViewModel class, which is the bridge between the view and the model. Each View class has a corresponding ViewModel class.
  7. MVVM on Android #1 public class MyFragmentViewModel { private Listener

    listener; public void initialize() { listener.onVisibilityFlagChanged(true); } public void setListener(Listener listener) { this.listener = listener; } public interface Listener { void onVisibilityFlagChanged(final boolean visible); } }
  8. MVVM on Android #2 public class MyFragment extends BaseFragment implements

    MyFragmentViewModel.Listener { MyFragmentViewModel myFragmentViewModel; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); bindViewModel(); } private void bindViewModel() { myFragmentViewModel.setListener(this); myFragmentViewModel.initialize(); } @Override public void onVisibilityFlagChanged(boolean visible) { // do some magic
  9. Why RoboBinding? • Still developed and maintained • +400 stars

    at GitHub • Easy to use and extend • Annotation processing and code generation
  10. Robobinding history • Created in 2011 by Robert Taylor &

    Cheng Wei • Added code generation in version 0.8.9 in October 2014
  11. RoboBinding - setup #1 buildscript { repositories { jcenter() mavenCentral()

    maven() { url 'https://oss.sonatype.org/content/repositories/snapshots' } } dependencies { classpath 'com.android.tools.build:gradle:0.14.2' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }
  12. RoboBinding - setup #2 apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt'

    apt("org.robobinding:codegen:$robobindingVersion") { exclude group: 'com.google.android', module: 'android' } compile("org.robobinding:robobinding:$robobindingVersion") { exclude group: 'com.google.android', module: 'android' }
  13. Android & RoboBinding - hello world @PresentationModel public class MainViewViewModel

    implements HasPresentationModelChangeSupport { private PresentationModelChangeSupport changeSupport; private String name; public MainViewViewModel() { changeSupport = new PresentationModelChangeSupport(this); } public String getHello() { return name + ": hello Android MVVM(Presentation Model)!"; } public String getName()..... public void setName(String name) …. public void sayHello() { changeSupport.firePropertyChange("hello"); } @Override public PresentationModelChangeSupport getPresentationModelChangeSupport() { return changeSupport; } }
  14. Android meets MVVM - hello world public class MainActivity extends

    Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainViewViewModel presentationModel = new MainViewViewModel(); View rootView = Binders.inflateAndBindWithoutPreInitializingViews(this, R.layout.activity_main, presentationModel); setContentView(rootView); } }
  15. Android meets MVVM - hello world <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:bind="http://robobinding.org/android"

    tools:ignore="MissingPrefix" android:orientation="vertical"> <TextView …….. bind:text="{hello}"/> <EditText ……. bind:text="${name}"/> <Button …. android:text="Say Hello" bind:onClick="sayHello"/>
  16. ListView, GridView and co. @ItemPresentationModel(value=StringItemPresentationModel.class) public List<String> getItems() { //return

    some items.. } <ListView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" bind:itemLayout="@layout/simple_list_item" bind:source="{items}" />
  17. ListView, GridView and co. #2 public class StringItemPresentationModel implements ItemPresentationModel<String>

    { private String value; @Override public void updateData(String bean, ItemContext itemContext) { value = bean; } public String getValue() { return value; } }
  18. Adding new bindings • Just implement PropertyViewAttribute or TwoWayPropertyViewAttribute interface

    if needed • Create binding by implementing ViewBinding interface and map PropertyView classes to the binding name • Register binding
  19. Unit tests • Our ViewModel is separated from UI Android

    dependencies so we create unit test without any problems @Test public void testShouldNotFail() { this.presentationModel.setA("2.0"); this.presentationModel.setB(1.5); assertEquals(expectedValue, this.presentationModel.getResult()); }
  20. RoboBinding Pros • minimize boilerplate code • easy to use

    • easy to extend • fast • pure POJO ViewModels = easy unit tests Cons • still not everything is supported (ListView with multiple item layouts, RecycleView)