ARCHITECTURAL PATTERNS IN ANDROID: Introduction
Programming for Android is a very broad field of work that requires a lot of knowledge. An Android app is not only a user-interaction screen (front-end), but also a back-end application, which may also include database management, while at the same time paying a lot of attention to performance and responsiveness, and thus to distributed work on the different (necessarily) threads. What in a microservice web application we find divided over different applications, perhaps even running on different servers, in Android we find it all in a single application, running in the palm of your hand. It is not a world, but a cosmos: a microcosm containing galaxies of concepts to be known and to be familiar with, and in which it is also easy to get lost. But fear not: we at AIknow can give you some advice to keep your spaceship on course, conquering the Android universe, starting with the first planet: architectural patterns in Android, how to set up the architecture of your application in an orderly and efficient manner.
BASIC CONCEPTS
For those who are not already familiar with Android, we present a quick overview of the basic elements. The starting point of every Android project is the Activity. By Activity we mean an application functionality, consisting of
- a graphical part for interacting with the user. It consists of an XML file that can also be ‘designed’ visually in a special section of Android Studio.
- a logical part, i.e. the operations to be performed at start-up and/or in response to user actions. It consists of a Java or Kotlin class that extends the Android AppCompatActivity class.
Every Android application contains at least one Activity. If the application contains several activities, one of them is labelled as the main Activity and is executed first each time it is started, and from it one can navigate (via buttons or otherwise) to the other Activities.
Each Activity can be subdivided into several sub-elements, or fractions of the same functionality, called Fragments. Exactly like the Activity, the Fragment is also composed of an XML and a Java or Kotlin class. Each Activity or Fragment possesses a lifecycle, i.e. a series of methods that are executed as a consequence of operating system events. To name a few:
- onStart(): the activity (or fragment) was started
- onResume(): the activity (or fragment) was ‘resumed’ after a paused state
- onPause(): the activity (or fragment) was paused (e.g. because a phone call came in or the screen was locked)
- onDestroy(): the activity (or fragment) was destroyed (e.g. because a new activity was switched to or the app was closed)
For those who try their hand at writing their first Android app with Android Studio, after having familiarised themselves with the concepts of Activity, Fragment and lifecycle, it may come natural to add to the Activity all the Java (or Kotlin) code needed to retrieve data from the database, display it on the screen, manage events, notifications, call APIs… This is understandable, but the risk with such an approach is that the Activities and Fragments reach astronomical dimensions, and contain many different tasks, not to mention the difficulty of maintaining order in the midst of all this welter of code. To remedy this problem, or at least reduce these risks, architectural patterns come to our aid.
ARCHITECTURAL PATTERNS: WHAT AND WHY
Architectural design patterns (from Wikipedia) express basic patterns for setting the structural organisation of a software system. An architectural pattern is therefore a set of tricks to be followed to keep the layers that make up our app well separated. It is not necessary for the proper functioning of the app, however it is a fundamental tool for:
- maintaining order in large applications: a neat and tidy application is much easier to maintain and evolve, and therefore less costly
- to set up the architecture of a small app that might be scaled up in the future: using an architectural patter makes it possible to scale up nimbly, without having to undertake costly total refactoring.
- easily test individual portions of business logic or UI
In the following paragraphs, we will describe, with practical examples, one of the most popular architectural patterns in Android, the MVP pattern.
MVP (Model – View – Presenter)
Son of the well-known MVC (Model – View – Controller), one of the best-known architectural patterns in object-oriented programming, MVP is a very similar pattern used in Android programming, in which the Presenter takes the place of the Controller.

The objective of MVP (as well as MVC) is to separate presentation logic from business logic. MVP and MVC differ in the way the three elements communicate with each other (more on this in a moment). Let us review the three components:
MODEL
The Model is the layer that is in charge of managing data, i.e. providing or updating, regardless of what the source is (database, preferences, api). The application layer that requests the data (the Presenter) is agnostic as to how the data is retrieved: it is up to the Model to apply the necessary logic to ensure that the requested data is provided. For example, an app might have a StarshipsRepository class with a getStarships() method that returns the list of spaceships by applying the following logic:
- if the device is connected to the Internet, it calls an external API to obtain the updated list of spaceships
- if the device is offline, it shows the spaceships saved in the database.
The Model must also consist of classes that do not extend the Android classes (Activity, Fragment, etc.), and must not have direct references to them. Only the Presenter classes can directly call the Model classes to obtain data. In this, the MVP pattern differs from the MVC pattern, in which instead the Model classes can interact directly with the View classes.
@Singleton
public class StarshipsRepository {
private ConnectivityManager connectivityManager;
private EngineManager engineManager;
public List getStarships() {
if (isNetworkAvailable()) {
return this.serverApiManager.getStarships();
} else {
return this.databaseManager.getStarships();
}
}
public void launch() {
// to implement: launch a starship
}
...
}
VIEW
In the architectural patterns in Android, a View, on the other hand, is the layer that deals with interacting with the user. Thus, the View includes all the Activities, Fragments, and, more generally, all the classes that represent views, that is, the visual elements that display data and take up user actions (touches on the screen, gestures, use of the camera, etc.). Views must be ‘dumb’ in the sense that they must not contain business logic, but only handle user interaction and forward input to the lowest application layer (the Presenter). so as to ensure separation of tasks (as far as possible, remember that patterns must be an aid, not a limitation). The View layer simply has two tasks:
- Receive user interactions with the device and forward them to the Presenter
- Expose methods that receive input data to be displayed, and display it to the user.Expose methods that receive input data to be displayed, and display it to the user.
These methods must be used by the Presenter. The View therefore has a special role: it does not owe the application logic, but at the same time, being subject to the lifecycle, everything begins and ends with it, so the whole application depends on it. It can do its own thing, and the other application layers can only adapt as best they can.
public class StarshipFragment extends Fragment implements StarshipContract.View {
// Il Fragment (la View) ha un riferimento con il proprio Presenter
private StarshipContract.Presenter starshipPresenter;
private RecyclerView mRecyclerView;
protected RecyclerView.LayoutManager mLayoutManager;
private FloatingActionButton takeOffButton;
public StarshipFragment() {
this.starshipPresenter = new StarshipPresenter(this);
}
public static StarshipFragment newInstance() {
return new StarshipFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_starship, container, false);
// ************************
// Launch button
// ************************
takeOffButton = root.findViewById(R.id.takeOffButton);
// Ad ogni click sul pulsante, il Fragment non fa altro che chiamare un metodo del Presenter
takeOffButton.setOnClickListener( click -> starshipPresenter.launchStarship());
// ************************
// Starships list
// ************************
mRecyclerView = (RecyclerView) root.findViewById(R.id.starshipOverview);
mLayoutManager = new LinearLayoutManager(getActivity());
setRecyclerViewLayoutManager();
mRecyclerView.setAdapter(starshipsListAdapter);
return root;
}
@Override
public void onResume() {
super.onResume();
// Ogni volta che il Fragement si avvia (o si riavvia) si esegue il metodo start() del Presenter
// come detto, ogni decisione (comprese le operazioni da fare all’avvio) sono delegate al Presenter
starshipPresenter.start();
}
// ###########################################################
// Override from contract
// ###########################################################
@Override
public void showStarshipsList(List starshipList) {
this.starshipsListAdapter.updateList(starshipList);
}
@Override
public void showErrorMessage(int error) {
snackbar.setText(getString(error));
snackbar.show();
}
...
}
PRESENTER
The Presenter is the holder of the business logic. We have to imagine him as the captain of a (space) ship: he assigns tasks to the various crew members and is responsible for making decisions that affect the fate of the ship. He interacts with both the Model and the View:
- The View receives user input and ‘decides’ what to do with this input, applying the actual application logic.
- From the Model it decides which data to retrieve, and passes it to the View to be displayed to the user.
The Presenter also has the very important task of orchestrating the threads correctly. Without going into too much detail, it must prevent the main thread (dedicated to the UI) from being employed in computationally burdensome operations, which could lead to a drop in responsiveness (or even to an app crash, the nightmare of every Android programmer). To do this, it assigns to the main thread only the minimal operations that are indispensable for the UI to function, while all other operations (read/write operations, calls to external APIs, etc.) it assigns to specific threads. The Presenter, not being an extension of an Android class, and thus having no lifecycle, depends on the View. Its very existence depends on the View. The Presenter can therefore be considered as a tool, available to each View, to take all the business logic away from it, to lighten it and separate tasks.
public class StarshipPresenter implements StarshipContract.Presenter {
private StarshipsRepository starshipsRepository;
private EngineManager engineManager;
private final StarshipContract.View mView;
public Mag5Presenter(StarshipContract.View mView) {
this.mView = mView;
}
// ###########################################################
// Override from contract
// ###########################################################
@Override
public void start() {
GetMag5TransportItemsList_CB cb = new GetMag5TransportItemsList_CB();
Disposable d = this.starshipsRepository.getStarships()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> mView.showStarshipsList(result),
error -> mView.showErrorMessage(R.string.error_fetching_item_mag5)
);
addDisposable(d);
}
@Override
public void launchStarship() {
if (this.engineManager.isEngineReady())
this.starshipsRepository.launchStarship();
}
...
}
CONTRACT INTERFACES
Contract is an element of the MVP pattern which serves primarily to maintain order in the project, and to ensure that one of the ‘rules’ of the pattern is observed:
Each View class must correspond to a Presenter class, with a 1:1 correspondence
The idea is the following: for each View class there must be one and only one Presenter class (and vice versa), and the two are meant to work together, stipulating a sort of contract: as if it were a team where the Presenter is the mind, the one who decides, the View is the arm, the one who executes, but the two are complementary and work as a team to implement the same functionality. Contracts are interfaces that serve precisely to enshrine this bond between each View and its Presenter. They in turn contain two interfaces, one for the View and one for the Presenter, which in turn contain the signatures of the corresponding methods. In this way, when looking at a Contract class, it is possible to see at a glance what has been implemented in a View/Presenter pair, as if they were one and the same thing.
public interface StarshipContract {
interface View {
void showErrorMessage(int messageCode);
void showStarshipsList(List starshipList);
}
interface Presenter {
void start();
void launch();
}
}
CONCLUSION
Architectural patterns in android are a fundamental tool for making your android app neat, maintainable and scalable. In this article we explore the MVP (Model View Presenter) architectural pattern with a few examples. And don’t forget to check out our other blog news or our use cases to see what kind of work we have done in AIknow!
Do you need an app to digitise a process? Want to know more?


