5min Tech | Common App architectural principles | by Beney Chen | May, 2024

A typical Android app contains multiple app components, including activities, fragments, services, content providers, and broadcast receivers. Most of which are declared in your app manifest. Then Android OS then uses this file to decide how to integrate your app into the device’s overall user experience.

Keep in mind that mobile devices are also resource-constrained, so at any time, the operating system might kill some app processes to make room for new ones.

Since the killing events aren’t under your control, you shouldn’t store or keep in memory any application data or state in your app components and your app components should depend on each other.

Separation of concerns.

This is most important principle. It’s a common mistake to write all your code in an Acitvity or Fragment. While these UI-based classes should only contain logic that handles UI and operating system interactions.

The better approach is to keep these classes as clean as possible, so that you can avoid many problems related to the component lifecycle, and improve the testability of these classes.

Since that you don’t own implementations of Activty and Fragment. Rather, these are just glue classes that represent the contract between the Android OS and your app. The OS can destroy them at any time based on user interactions or because of system conditions like low memory. To provide a satisfactory user experience and a more managable app maintain experience, it’s best to minimize your dependency on them.

Drive UI from data models.

This means that data model should store separately to viewModel to avoid tieing to the UI and app component lifecycle, but will still be destroyed when the OS decides to remove the app’s process from memory.

Persistent models are ideal for the following reasons:

  • Your user don’t lose data if the Android OS destroys your app to free up resources.
  • Your app continues to work in cases when a network is flaky or not available.

Single source of truth

When a new data type is defined in your app, it’s better to assign a Single Source of Truth (SSOT) to it. You can see it as the only owner of the data that can mutate it. To achieve this, the SSOT exposes the data using an immutable data type, and also exposes functions or receive events that other types can call.

This pattern brings multiple benefits:

  • It centralizes all the changes to a particular type of data in one place.
  • It protects the data so that other types cannot tamper with it.’
  • It make the changes to the data more traceable. Thus, bugs are easier to spot.

For offline-first application, the SSOT for application data is typically a database. In some other cases, the souce of truth can be a View Model.

Unidirectional data flow

The SSOT is often used with the Unidirectional Data Flow (UDF) pattern. In UDF, state flows in only one direction. The events that modify the data flow in the opposite direction.

For example, application data usually flows from data sources to the UI. User events such as button presses flow from the UI to the SSOT where the application data is modified and exposed in an immutable type.

This pattern better guarantees data consistency, is less prone to errors, is easier to debug and brings all the benefits of the SSOT pattern.

Have a great day:)

Leave a Reply