NewsFly ✈️ An app featuring MVVM, Navigation Component, Flow, Pagination, Search, Room, Data Store, Hilt (Clean Architecture)
I’ll be showing you how to build an all in one ‘News application’ which features virtually every thing you would ever need in building a modern performant android application.
I call this application — NewsFly ✈️
Features
- Architecture — MVVM
Guide to app architecture | Android Developers - Live Data and Flow
Article on flow and live data - Navigation Component
Get started with the Navigation component | Android Developers - Hilt
Dependency injection with Hilt | Android Developers - Pagination
https://developer.android.com/codelabs/android-paging - Data Store
DataStore | Android Developers - Room
Article on offline Storage - Data Binding and ViewBinding
Article on binding
….Light and Dark Mode, Offline Capability, Search, Retrofit, Glide, Shimmer View and lots more 🌝
Final App
Here is what our final app will look like:
Full Code
If you are the type that just wanna jump straight to the codebase, I got you covered:
Link to full code on github
What to do before moving on with this article?
You have to check the full code on GitHub for dependencies used, xml used (Layouts, Custom views) and other classes.
In order to reduce complexities, this article focuses on:
Retrieving, Storing and Displaying of data (news)
Architecture
The architecture used for this application is:
MVVM — Model - View - View Model.
I would explain this using the diagram below: (Pay attention 👀)
Let’s start from the ground up (Bottom), all the way to the top from fig 1.
Using the diagram above, we would take each of the layer and see how they all connect to build a well structured application. (NewsFly ✈️)
WebService:
In simple terms, this layer consist of HOW and WHERE you are getting your data from (In this case, a list of news post)
How and Where?
How: Retrofit
Where: NewsApi
I would assume you have Retrofit setup using hilt. If not, check how I did same in this article
- Create a Package: Name that → “
network
” - Inside “
network
” package, create a new Interface, Name that → “ApiService
”
So, now that we know where we want to get our news articles from, what’s next?
More Layered Structure
This is not necessary, but I love to have a “middle man” that interacts with ApiService
”
- Create a new package, name that →
data
- Under
data
, create a new Kotlin File/Class, call that → “ApiDataSource
“
- As you can see, I made a reference to “
ApiService
” using hilt, which we created earlier under “network
” package - Using Coroutines, we perform the magic of making the network request “asynchronously”
SQLITE
The next thing shown in our reference image (fig 1
) (bottom left) is SqLite.
SqLite is basically a relational database management system.
We want our users to be able to view some contents when the app is offline (without internet) or with a slow internet connection.
How to achieve this:
Room Database
If you are new to room database, check this article I wrote:
Article on room to get an overview of storage on android
- Create a new
Package
, call that “database
” - Under “
database
”, create 3 new packages call them →dao
,entity
, andmain
- Under
entity
, create 2 new classes →RecentArticle
andAllNewsRemotekey
[These are our Model (Seefig.1
)]
RecentArticle
A model of how the response from our api looks like. We would save this in a table called recent_articles in room database
Serializable
means this whole entity or object can be passed as a byte stream to an activity or fragment (UI layer).
Okay, quick pause ⏸. Do you want to display ALL our data gotten from our remote data source to the user at once 🤔? 20,000 articles at once.? Do You?
Imagine if Instagram displays the whole photos of the 5,000 people you are following on your feed at once. (That will be horrible), why? → Your data gets consumed in one instance, you get to an almost never-ending loop of posts.
Solution:
Pagination
We will have to implement a mechanism of showing just the list of posts a user can consume on the screen at the moment.
As the user scrolls down→ We display more posts from our data source. That way, less data is consumed.
AllNewsRemotekey
We would save a reference to the next
and previous
pages of our response from our api in room database, call that table → all_news_remote_keys
Now lets see how we are going to query these items which we want to save and retrieve from the tables we have set up above
- Under
dao
package create 2 new Kotlin File/Classes name them →ArticleDao
andAllNewsRemoteKeysDao
- Dao means —
Data Access Object
ArticleDao
- It is self explanatory → We want to Insert, Get, and Delete news articles into or from our database
AllNewsRemoteDao
Also self explanatory — Operations carried out on all_news_remote_keys table.
Repository
We are now at the repository layer (From fig 1
).
Repository modules handle data operations.
They provide a clean API so that the rest of the app can retrieve this data easily. They know where to get the data from and what API calls to make when data is updated. You can consider repositories to be mediators between different data sources, such as persistent models, web services, and caches.
- In data package, create 2 new
Kotlin File/Class
, call them →AllNewsRemoteMediator
andAllNewsRepository
AllNewsRemoteMediator
What this class does is simple → Get data from the network and “incrementally” store them into local database (Room).
This is provided by the pagination library.
AllNewsRepository
Using flow and the remote mediator created above, we perform the operation of getting the news items (articles).
PagingConfig()
defines howPagingSource
should load the data.pageSize
Defines the number of items loaded at once from thePagingSource
.maxSize
Defines the maximum number of items that may be loaded intoPagingData
before pages should be dropped.prefetchDistance
defines how far from the edge of loaded content an access must be to trigger further loading.enablePlaceholders
indicates whether you want to display placeholders when loading the data.
ViewModel
This is part of JetPack’s class which helps to store and manage UI related data in a very conscious way. → This way, even if you rotate your device, your data don’t get lost.
From the diagram in fig. 1
you would see that our ViewModel communicates with our Repository for storing and obtaining data.
- Create a new package, Name that → viewmodel
- Create a kotlin class/file, name that → AllNewsViewModel
AllNewsViewModel
- Using hilt, we inject a reference to our repository
- Create a function used to get recent news with returns a flow → of paginated articles data all cached in the context of a viewModelScope.
Activity/Fragment
Finally, we are at the top layer of fig.1
😌
This is where all the UI related stuff comes in place.
As you can see from the diagram, we only need to have a reference to our viewModel.
Our application makes use of a single activity which hosts our various fragments (Using navigation component).
- Create a new package, call that → ui
- In the
ui
package, create a new package, call that fragments - Inside
fragments
package, create a new fragment called HomeFragment
HomeFragment
- First, set up your recycler view
As you can see, we bind our recyclerView adapter with our adapter.
One of them is used for displaying our paginated news (RecentNewsAdapter) while the other is used for handling retries when something wrong happens while loading the data (AllNewsLoadStateAdapter)
Please, check full code for:
- RecentNewsAdapter.kt
- LoadStateAdapter.kt
- Next, we SAFELY collect our data (news article list)
Now, you have a well crafted, layered application with pagination and all the fancy new stuffs released and recommended by the android team (As at 8th, October, 2021 😏).
Thanks for reading!🤞
Contact Me
https://linktr.ee/Ibrajix