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

Custom Views as components - DroidJam '18

Custom Views as components - DroidJam '18

How will you organize your android app's 10k+ lines of code written by group of people? In a couple of months, before you know it, it'll cross a 100k lines. Wouldn't it be great if when a new feature requirement comes, you create a new class and start working on it, rather than worrying about what other things might break if you edit this 5k lines Activity/Presenter class?

Enter components.
Components are intuitive! They let you split your code into independent, reusable pieces, and think about each piece in isolation- great for abstraction and modularization.

Developers don't realize that rather than fragments, they can create custom views and use them as components. Views are light-weight and don't blow up in your face with the infamous IllegalStateException. You don't need any libraries or learn a new programming paradigm to get started.

In this talk, I go through how to get started with views, how using views has made my teams' lives easier, some common patterns implementing different use-cases and how to unit test.

Vedant Agarwala

July 13, 2018
Tweet

More Decks by Vedant Agarwala

Other Decks in Programming

Transcript

  1. WITH MV* Sorry jim, but you have drawn the short

    straw after 2 hours of discussion on the interfaces…
  2. — The new GO-JEK rider app (COMPONENTS) CAN CONTAIN BOTH

    UI AND BUSINESS LOGIC ” “ https://blog.gojekengineering.com/an-architectural-overview-of-the-new-go-jek-rider-app- bb1dbd174323
  3. THE CONSTRUCTOR CREATE A CUSTOM VIEW MyAwesomeComponent(…) : FrameLayout(…) {

    // This is an actual constructor, unlike // onCreate() and onCreateView() that just // look like constructors, but aren’t. init { View.inflate(context, R.layout.view_my, this) } }
  4. PASS IN THE DATA CREATE A CUSTOM VIEW class AddEditRootView(…)

    { /** * Pass in the data */ fun showTaskWithId(id: String?) { id ?: return context.getTasksRepository().getTask(id) .subscribe { task -> mTask = task add_task_title.setText(task.title) add_task_description.setText(task.description) } }
  5. CREATE THE DEPENDENCY SETUP THE DEPENDENCIES class MyApplication : Application(),

    TasksRepositoryFactory { override val tasksRepository: TasksRepository by lazy { … } } interface TasksRepositoryFactory { val tasksRepository: TasksRepository }
  6. FETCH THE DEPENDENCY SETUP THE DEPENDENCIES /** * Calls the

    correct implementation of application * based on the manifest or roboletric properties */ fun Context.getTasksRepository() = (applicationContext as TasksRepositoryFactory) .tasksRepository
  7. SETUP FOR EVERY SCREEN THE STATUS QUO - UNIT TESTING

    IN MVP For every screen, we additionally need a: 1.ViewContract 2.PresenterContract 3.DaggerModule 4.Presenter
  8. VERIFY METHOD CALLS IN TEST THE STATUS QUO - UNIT

    TESTING IN MVP verify(mockedClass).methodCall(withArgs) // saved to the model verify(mTasksRepository).saveTask(any(Task.class)); // shown in the UI verify(mAddEditTaskView).showTasksList();
  9. THE SETUP UNIT TESTING IN COMPONENTS class TestApplication : Application(),

    TasksRepositoryFactory { override val tasksRepository: TasksRepository by lazy { // create a test repo object … } } # robolectric.properties application=mocks.TestApplication
  10. “GLOBAL” DEPENDENCIES UNIT TESTING IN COMPONENTS Now context.getTasksRepository() returns the

    test object. Magic! No need for: @Mock private TasksRepository mTasksRepository; @Mock private AddEditTaskContract.View mAddEditTaskView; in your tests.
  11. COMPARISON UNIT TESTING IN COMPONENTS // saved to the model

    verify(mTasksRepository).saveTask(any(Task.class)); // shown in the UI verify(mAddEditTaskView).showTasksList();
  12. TESTING TIME WITH ROBOLECTRIC No doubt slower than JUnit. 5

    sec with JUnit vs 10 sec with Robolectric. It reduces the number of espresso tests which decreases complete-test times. You will still have JUnit tests (for the data repositories, for example). Robolectric speed will only increase with sub- sequent versions.
  13. onPause() Components are intuitive and much more modular. Fully unit

    testable via robolectric. You probably don’t need the lifecycle callbacks or onSaveInstanceState provided by Fragments. Easy to learn and implement in a team- No abstractions for tests.
  14. TRADE OFFS It adds another layer in your test pyramid,

    between JUnit and espresso. If your use case needs a lot of among interactions, you may need to do a MV* inside that view. No silver bullet for transitive state management