Clean architecture in Flutter — kick-off

Mateusz Zając
3 min readMay 13, 2021

--

This article shows an approach to Clean Architecture by Uncle Bob in Flutter. Demo app fetches posts from public API and displays them inside ListView. I’ve decided to use GetIt as a service locator and Chopper for API calls.

Flow diagram

Main file initialises the service locator and opens the list screen.

Presentation layer

Screens

This package is divided by screens. Every has its own main widget (here called screen), optional subdirectory with widgets used on that screen and bloc (Business Logic Component) implementation.

Screen widgets most of the time are Scaffolds which makes it easy to implement material design page components.

If the screen does some business logic it has to communicate with bloc. To do that use BlocBuilder inside the widgets hierarchy. Builder method refreshes views based on received state. See below how refresh indicator appears on LoadingState and is replaced by ListView when data comes.

Bloc

The core function in Bloc is the mapEventToState method. It receives events sent by widgets, handles longer operations calling usecases and “returns” data by yielding state to all listening widgets. That means you can listen to the same bloc in more than one widget.

Usecases are provided in constructor by service locator.

Events and States could be extracted to separate files, but for sure they clearly describe all business actions — what user can do on that screen and how app responds to that actions on UI.

Last but not least is initial state. Either it’s EmptyState or LoadingState it’s important to display some info on UI rather than a blank white page.

Domain layer

Entities

Business object models of application. They may reference each other. They may contain methods. But they CAN’T know about other packages outside entities.

Repositories definitions

Abstract repositories, which have implementations in the data layer.

Usecases

Make one or more operations using repositories.

Data layer

Network

Data source handles integration between network and domain objects. It converts from network response to domain entity object.

Chopper annotated services make API calls using HttpClient, but definitions of request are easily readable.

Mappers

JSON to/from Entity functions. Unfortunately Dart doesn’t support static methods implementation inside extension :/

Repositories

Implementation of previously defined interfaces from domain layer. They can make use of one of more data sources. It’s a good place to fetch data from the network and store it locally to minimize network calls.

Summary

Final result should look like below. I believe that one was easy to understand and the next one will take care about caching multiple data sources and streams in usecases.

--

--