This is a project that accompanies a lecture on software architecture. The 2022 recording is available on YouTube. The description of this app starts with this slide. This is a simple application that contains a list of articles. You can bookmark or delete each article. The list of articles and their authors are loaded asynchronously and combined using the author id.
- The project is structured by architecture layers, i.e. there are folders data, domain and ui. This is done for demonstration purposes, and this is not how we usually structure applications. Usually classes are divided into modules by feature, for example, all classes associated with an article will be located in the article folder, and, as a rule, there will be fewer folders, and the project structure will be flatter.
- This lecture precedes a lecture on Dependency Injection, so all the code related to DI is written manually. In real projects, DI frameworks should be used to avoid boilerplate code. The most popular choice for large projects is Dagger 2.
Data is loaded from the HardCodedDataSource
. It uses delays to simulate asynchhronous loading.
Repositories (ArticleRepository
and AuthorRepository
) are responsible for retreiving the data from data source and caching it into LiveData
s.
(ArticlesWithAuthorsUseCase is observing LiveData
s from the repositories and merges them into one LiveData<ArticlesWithAuthor>
using MediatorLiveData
.
(ArticlesViewModel
is observing this MediatorLiveData
. It maps ArticlesWithAuthor
into ArticleItemModel
using Transformations.map
to prepare the data for displaying.
Classes that are displaying data observe the LiveData
of the ViewModel
. There is an ArticlesFragment
that delegates most of its work to ArticlesViewController
to move code out of the system-managed classes.
ArticlesViewController
observes changes of the ViewModel
and pushes new data int ArticlesListAdapter
.
User events and data loading requests are propagated upwards using the usual and suspend
method calls. Whenever data changes, all classes get their updated version via LiveData
subscriptions, and the user interface is updated automatically.
A single source of truth ensures that all data is consistent and up-to-date.
On the slide each next lifecycle is nested inside the previous one. Accessing classes with one lifecycle from the classes with another lifeycle should be done with care to avoid memory leaks. On the slide, each next lifecycle is nested in the previous one.
Components are responsible for creating classes, obtaining the required dependencies, and storing references to the created classes. Usually each component is tied to one lifecycle, but there can be multiple components in each lifecycle.