How I managed to clean up my Activities and Fragments

Michał Smutkiewicz
AndroidPub
Published in
4 min readAug 16, 2019

--

One smooth pattern completely changed the way I organize my Activities and Fragments now. I’ve tried out a lot of different approaches, until I found one that is extremely easy to implement, use and maintain. The main trick of this pattern is that instead of creating a lot of potentially spaghetti code (setting up view components in several places, having to analyze long path of calls every time when something in UI doesn’t work properly, etc.), we divide our View code into States. The approach doesn’t require a lot of effort to refactor already written code and makes it cleaner and easier to debug.

This pattern was highly inspired by Ray Wenderlich’s article about MVI Pattern in Android, but in this tutorial we’ll make it independent from any architectural approach (I use MVVM aswell).

Implementation in steps

1. Base interfaces

We’ll start our journey with interfaces. BaseView is an interface that is implemented by all Activities or Fragments in our project (let’s treat them like Views). First that I had to understand is that our Views should always be in known state. Every View should have its own set of states and there should be one method to switch between them. The method can be called render() and should take next state to render as an argument. Each state used by View should be implementing interface ViewState.

2. Base implementation

Now let’s implement BaseView in one of our Views. To make it compile, we should implement render(state: BaseView.ViewState) function to render all our states:

In this function, we will switch between state classes for the one passed as an argument and fire function rendering desired state. Before we can implement body of this function, we should create a nested sealed class that will be treated as “a set of View States”. It should implement BaseView.ViewState:

Remember about private access modifier, as we don’t want other Views to access our internal View states.

3. Planning and implementing View States

Now, let’s make a couple of states — think about what possible states can your View have. Suppose we need something to start our components -InitialState, load data -LoadingState, present our data -DataState, show errors if needed -ErrorState, show details of a chosen item - DetailState and go away from the View -FinishState.

There is a set of states that are common in each View. Consequence can be an essence and power of this pattern, so be consequent and use basic set of states in similar way in all Views, to easy understand code later:

  • In InitialStates, init your UI components, Broadcast Receivers, adapters, without any data fetching,
  • In LoadingStates, activate your loading UI components and fetch data from servers,
  • In DataStates, show ready data and wait for any action from the user,
  • In ErrorStates, show all AlertDialogs and any error messages to user,
  • In FinishStates, cleanup everything that is needed before exiting the Activity.

4. Finally, render your States

Now, we can implement render function:

Every time we will be switching between states in View, we will call render(MoviesActivityState.StateClass()). As a result, associated function will be called. As we can also see, some of state classes are just objects and some are data classes with properties to use inside them. For example, once we are leaving LoadingState with a list of movies as a result, we can easily pass them to DataState:

In above function, we fetch list from servers through API on IO-context coroutine (big love ❤ for Coroutines in Kotlin) and once finished, assign fetched data and fire next state, passing new data.

Of course, we have to implement all associated functions for each state, that’s how it looks:

Why I like that pattern so much?

I’ve checked it out in practice and this really makes life easier. What are advantages and disadvantages the pattern in Android:

Pros:

  • No more spaghetti code in Activities and Fragments, pattern used properly, provides logic easy to understand,
  • A consistent state during the lifecycle of Views,
  • Code easy to maintain and debug,
  • No more wondering where on hell have I switched off that Floating Action Button.

Cons:

  • Needs a while to implement contract (sealed class and render function) and it’s some kind of copy-paste work sometimes.

Practical Tips from my experience

There is a set of rules for this approach that I obey every time I’m using the pattern:

  • Our View should always be in some particular state,
  • Every State should not depend on actions done in previous state. For example we shouldn’t assume that DataState is called always after LoadingState, we should make independent, flexible States,
  • Every State function should somewhere call next state render. It would be nice to have possible next states called somewhere in current’s state associated function body wherever possible (it makes easier to understand a cycle of states).

We’re done!

That’s all for today, I started my internship in IT company this summer and I had pleasure to check out some different architectural approaches. I constantly try to improve my skills, make better code… and share what I’ve learned with other developers! :)

My last post on MindOrks about Material Design Components got about 500 claps. Thank you very much, hope you’ll also like this one ;) Don’t forget to 👏👏👏 and leave your opinions and comments :)

This time we’ll break the blog tradition and instead of Andie, paste Elliot Alderson for goodbye. Hope you won’t feel dissappointed ;) P.S - 4th and last season of Mr. Robot is coming this September!

References

--

--

Michał Smutkiewicz
AndroidPub

Android Developer / Telecommunications student @ WUT / mobile dev enthusiast / Android passionate / cat lover