The user opens the app and presses the start button.
After that the user puts their phone into their pocket and starts walking.
The app requests a photo from the public flickr photo search api for his location every 100 meters to add to the stream.
New pictures are added on top. Whenever the user takes a look at their phone,
they see the most recent picture and can scroll through a stream of pictures which shows where the user has been.
It should work for at least a two-hour walk. The user interface should be simple as shown on the left of this page.
- Kotlin - Modern programming language for Android development.
- Android Architecture Components - Collection of libraries that help you design robust, testable, and maintainable apps.
- ViewModel - Stores UI-related data that isn't destroyed on UI changes.
- Room - SQLite object mapping library.
- Navigation - A bit over the top for this single screen app, but I like how easy it is possible to add other screens with this library.
- Retrofit - A type-safe HTTP client for Android and Java.
- OkHttp - HTTP client that's efficient by default: HTTP/2 support allows all requests to the same host to share a socket
- Gson - used to convert Java Objects into their JSON representation and vice versa.
- Coroutines - Lightweight framework that simplifies multithreading on Android.
- Livedata - An observable data holder class.
- Coil - An image loading library for Android backed by Kotlin Coroutines.
- Hilt - Hilt is a dependency injection library for Android that reduces boilerplate.
- DataBinding - The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.
- Mockk - Mocking library for Kotlin.
- Espresso - For Android UI tests.
I chose an MVVM architecture with the following layers:
- Domain - Would execute business logic which is independent of any layer.
- Data - Where the data from remote or cached source is handled.
- Presentation - The role of the presentation layer is to display the application data on the screen.
We're all used to monolithic Android applications, where all your classes are inside one module divided into multiple packages. Unfortunately, this approach tends to lead to high build times, difficulties to manage code in large teams and impossibility to reuse code across apps.
Although we're not gonna take this approach here as this app is really simple, there are useful resources on the subject:
- Modularizing Android Applications - By Joe Birch.
- Create an Android Library - Android Documentation.
For the simplicity of things we'll create a monolithic with two different packages: core and features. core contains all the common/reusable code and features contains two features: photos and tracking.
- photo by: Android Guide to Architecture
Nb: In the illustration above the UI layer would be our presentation layer
That is for our global vision. Now if we want a more refined one, this graph would be suitable:
- photo by: Android Guide to Architecture
Let's take each element one by one and see how it links to this project:
- Activity/Fragment - This is our MainActivity hosting our PhotosFragment. (presentation layer)
- ViewModel - PhotosFragment's PhotosViewModel observes a stream of photos. (presentation layer)
- Repository - PhotoRepository interface with searchPhotoForLocation(lat: String, lon: String). (domain layer)
- Model - This is our Room database (PhotoDatabase with PhotoEntity objects). (data layer)
- Remote data source - PhotoService which call the Flickr API. (data layer)
For this purpose you need to perform location updates in the background. A service seems to be a good solution:
A Service is an application component that can perform long-running operations in the background
Then the other thing to figure out is to choose which service from three different types: Background, Foreground and Bound.
Each of these terms are misleading because it is not describing the behavior of how each service are used,
but it is describing how they are terminated.
- A Background Service is a service that runs only when the app is running so itโll get terminated when the app is terminated.
- A Foreground Service is a service that stays alive even when the app is terminated.
- And a Bound Service is a service that runs only if the component it is bound to is still active.
I decided to opt for a foreground service as I have more guarantees that the location will be tracked even though the app is killed.
Plus, we can associate a notification to it to notify the user that his location is being tracked.
Testing location tracking can seem difficult. But thankfully you can trace a route via your Android emulator.
We can just start tracking and trigger the route at the same time to simulate a hike.
Compose would have been welcome. I'm not 100% fluent on it so i didn't take risk of running into any hiccups.
Keep track of your different walks, and trace them on a map view with polylines.