In this tutorial, we will learn about Android Architecture Components: App architecture design is very important for ensuring that your apps are robust, testable, and maintainable. Android includes a set of libraries and components to assist you in building your app in accordance with best practices. We’ll also look at some simple snippets written in Kotlin, an amazing language that is now officially supported by Android.
Contents
What is Android Architecture Components?
The Android Operating system aggressively manages resources to perform well on a wide range of devices, which can make it difficult to build robust apps. Android Architecture Components guide app architecture by providing libraries for common tasks such as lifecycle management and data persistence.
Architecture Components assist you in structuring your app so that it is robust, testable, and maintainable with less boilerplate code. Architecture Components offer a simple, adaptable, and practical approach that relieves you of some common issues, allowing you to focus on creating great experiences.
Android Architecture Components Suggestions
To introduce the terminology, here is a brief overview of the Architecture Components and how they interact. Each component is discussed in more detail in the following section. This diagram depicts a simplified version of this architecture.
Entity: An entity is an annotated class that describes a database table when working with Architecture Components.
SQLite database: Data is stored on the device in an SQLite database. Additional storage options, such as a web server, are omitted from this chapter for clarity. This database is created and maintained for you by the Room persistence library.
DAO stands for data access object: A function-to-SQL query mapping. Previously, these queries had to be defined in a helper class, such as SQLiteOpenHelper. When using a DAO, you call the methods and the components handle the rest.
Room database: A database layer on top of an SQLite database that handles everyday tasks that you would normally handle with a helper class like SQLiteOpenHelper. Allows for more convenient local data storage. The DAO is used by the Room database to send queries to the SQLite database.
Repository: A class that you can use to manage multiple data sources, such as the QuoteRepository class.
ViewModel: Provides data to the UI and serves as an intermediary between the Repository and the UI. Hides the backend from the user interface. ViewModel instances survive changes to the device’s configuration.
LiveData: A data holder class that follows the observer pattern, which means that it can be observed. Always holds/caches the latest version of data. Notifies its observers when the data has changed. LiveData is lifecycle aware. UI components observe relevant data. LiveData automatically manages to stop and resuming observation, because it’s aware of the relevant lifecycle status changes.
Application Architecture Example
The diagram below depicts the same basic architecture form as the one above, but in the context of an app. The following sections get in full depth about each component.
Gradle files
To use the Architecture Components libraries, you must manually add the latest version of the libraries to your Gradle files.
Add the following code to your build.gradle(Module: app) file, below the dependencies block:
// Room components
|
Use the current version numbers
ext { |
Entity annotations
You must provide Room with information that relates the contents of the entity’s class (for example, Person) to what you want to represent in the database table in order for Room to work with an entity. This is accomplished through the use of annotations.
@Entity(tableName = ‘Quote table’) Each @Entity instance represents a table entity. Annotate your class declaration to tell Room that it is an entity. If you want the table’s name to be different from the class’s name, enter it here.
@PrimaryKey Every entity necessitates the use of a primary key. Add and annotate a primary integer key with autoGenerate=true to auto-generate a unique key for each entity, as shown in the code below. See Using Room entities to define data.
@NonNull Indicates that the return value of a parameter, field, or method can never be null. The @NonNull annotation should always be used on the primary key. This annotation should be used for mandatory fields in your rows.
@ColumnInfo(name=”quote”) If you want the column name to be different from the name of the member variable, specify the name of the column in the table.
Every field in the database that Room can access must be either public or have a “getter” method. Rather than exposing member variables directly, the code below provides agetQuote() “getter” method.
android architecture components, android architecture components , android architecture components , android architecture components , android architecture components , android architecture components
@Entity public class Person { @PrimaryKey (autoGenerate=true) private int id; @ColumnInfo(name = "first_name") private String firstName; @ColumnInfo(name = "last_name") private String lastName; // Getters and setters are not shown for brevity, // but they're required for Room to work if variables are private. }
You can also use annotations to define relationships between entities.
DAO (data access object)
You use data access objects, or DAOs, to access the data in your app using the Room persistence library. A Room database is built around a collection of Dao objects (DAOs). Each DAO contains methods that provide abstract access to the database of your app.
You annotate the DAO with SQL queries that you associate with method calls. The compiler validates the SQL and then generates queries based on the annotations. The libraries provide convenience annotations for common queries, such as @Insert, @Delete, and @Update.
Important Note:
- DAOs must be interfaces or abstract classes.
- Room makes use of the DAO to generate a clean API for your code.
- Queries (@Query) must be executed on a thread other than the main thread by default. If you use the appropriate annotations, Room will take care of thread management for you when performing operations like inserting or deleting.
- When you ask Room to insert an entity that already exists in the database, the default action is to ABORT. You have the option of specifying a different conflict strategy, such as REPLACE.
- Here is some code that demonstrates these annotations in conjunction with various types of queries:
@Dao public interface QuoteDao { // The conflict strategy defines what happens, // if there is an existing entry. // The default action is ABORT. @Insert(onConflict = OnConflictStrategy.REPLACE) void insert(Quote quote) // Update multiple entries with one call. @Update public void updateQuote( quote … quotes) // Simple query that does not take parameters and returns nothing. @Query("DELETE FROM quote_table") void deleteAll() // Simple query without parameters that returns values. @Query("SELECT * from quote_table ORDER BY quote ASC") List getAllQuote() // Query with parameter that returns a specific quote or quotes. @Query("SELECT * FROM quote_table WHERE quote LIKE :quote ") public List findQuote(String quote) }
LiveData
When you display data or use data in other ways in your app, you usually want to take action when the data changes. This implies that you must monitor the data so that you can respond when it changes. This can be difficult depending on how the data is stored. Observing data changes across multiple components of your app can result in explicit, rigid dependency paths between them. This makes testing and debugging difficult, among other things.
LiveData is a pattern in the architecture. It’s essentially a data holder for primitive/collection types. When it is active, it is used for observing changes in the view and updating the view. As a result, it is aware of the lifecycle.
- ViewModels, as we know, are used to communicate data to the View. Using ViewModels alone can be a time-consuming and expensive process because we must make multiple calls each time the data changes the View. In addition, we must store the data Model in different locations.
- LiveData, which is based on the Observer Pattern, helps to communicate between the ViewModel and the View.
Benefits of using LiveData:
- LiveData can be used with libraries such as Room Persistent Library, Coroutines, and others.
- When a set of data is modified or changed, the observers are notified. However, before notifying the observers, LiveData will check if the observer is live or not. If it is active, the notification will be sent, otherwise, it will not. As a result, the crash caused by disrupted activities will be prevented.
- You don’t have to worry about unsubscribing any observers when using LiveData.
- If an inactive observer is reactivated in the future, the most recent data will be sent to that observer.
- It is based on the observer pattern and ensures that your UI matches your data state. As a result, rather than requesting the data from ViewModel each time, we will be notified whenever the data changes.
- Prevent memory leaks — Observers are bound by the life cycle, and when the lifecycle is destroyed, the LiveData object is also destroyed.
- No more crashes as a result of stopped activities- If the observer’s lifecycle is inactive, such as in the case of a back stack activity, it does not receive any LiveData events.
- There will be no more manual lifecycle management – UI components will simply observe relevant data and will not stop or resume observation. Because LiveData is aware of relevant lifecycle status changes, it manages all of this automatically.
- Data that is always up to date — If a lifecycle becomes inactive, it receives the most recent data when it becomes active again. For example, when a background activity returns to the foreground, it receives the most recent data.
- Manage all configuration changes —When an activity or fragment is recreated as a result of a configuration change, such as device rotation, it receives the most recent available data right away.
If you are interested in learning more about LiveData, you can go through LiveData in Android with Example here I have explained LiveData in detail with suitable Examples in Android, and several scenarios in which LiveData can be useful. and I assure you that by the end, you will have a clear understanding of this commonly used technology.
MutableLiveData
You can use LiveData separately from Room, but you must manage data updates. However, there are no publicly accessible methods for updating the stored data in LiveData.
As a result, if you need to update the stored data, you must use MutableLiveData rather than LiveData. The MutableLiveData class includes two public methods for setting the value of a LiveData object: setValue() and postValue().
In most cases, MutableLiveData is used in the ViewModel, and the ViewModel only exposes immutable LiveData objects to the observers.
Observing LiveData
Create an observer of the data in the onCreate() method of MainActivity and override the observer’s onChanged() method to update the data shown to the user. When the LiveData changes, the observer is notified and the onChanged() function is called. The cached data is then updated, for example, in the adapter, and the adapter updates what the user sees.
The following code shows how to attach an observer to LiveData:
// Create the observer which updates the UI. val nameObserver: Observer<*> = object : Observer<Any?> { fun onChanged(@Nullable newName: String?) { // Update the UI, in this case, a TextView. mNameTextView.setText(newName) } } mModel.getCurrentName().observe(this, nameObserver)
Room database
Room is a database layer on top of an SQLite database. The Room takes care of mundane tasks that you used to handle with an SQLiteOpenHelper.
To use Room:
- Make a public abstract class that extends the RoomDatabase class.
- Annotations can be used to declare database entities and set the version number.
- If the database does not already exist, use Room’s database builder to create it.
- Create a database migration strategy. When you make changes to the database schema, you must update the version number and specify how to handle migrations. As an example, destroying and recreating the database is an effective migration strategy. A migration strategy is required for a real app.
Take note of the following:
- SQLite statements are checked at compile time by Room.
- Room does not allow you to run database queries on the main thread by default, in order to avoid poor UI performance. When necessary, LiveData applies this rule by automatically running the query asynchronously on a background thread.
- Typically, only one instance of the Room database is required for the entire app. Make your RoomDatabase a singleton to avoid having multiple instances of the database open at the same time, which is undesirable.
Here’s an example of an entire Room class:
@Database(entities = [Quote::class], version = 1) abstract class QuoteRoomDatabase : RoomDatabase() { abstract fun quoteDao(): QuoteDao? companion object { private var INSTANCE: QuoteRoomDatabase? = null fun getDatabase(context: Context): QuoteRoomDatabase? { if (INSTANCE == null) { synchronized(QuoteRoomDatabase::class.java) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder( context.getApplicationContext(), QuoteRoomDatabase::class.java, "Quote_database" ) // Wipes and rebuilds instead of migrating // if no Migration object. // Migration is not part of this codelab. .fallbackToDestructiveMigration() .build() } } } return INSTANCE } } }
Repository
A Repository is a type of class that abstracts access to various data sources. The Repository is not a component of the Architecture Components libraries, but it is a best practice for code separation and architecture. A Repository class is in charge of data operations. It provides a clean API for app data to the rest of the app.
A Repository manages query threads and enables the use of multiple backends. In most common cases, the Repository implements the logic for deciding whether to fetch data from the network or use database results cached locally.
Here’s the complete code for a simple Repository:
class QuoteRepository(application: Application?) { private val mQuoteDao: QuoteDao private val mAllQuotes: LiveData<List<Quote>> fun getAllQuotes(): LiveData<List<Quote>> { return mAllQuotes } fun insert(Quote: Quote?) { insertAsyncTask(mQuoteDao).execute(Quote) } class insertAsyncTask(dao:QuoteDao) : AsyncTask<Quote?, Void?, Void?>() { private val mAsyncTaskDao: QuoteDao override fun doInBackground(vararg params: Quote): Void? { mAsyncTaskDao.insert(params[0]) return null } init { mAsyncTaskDao = dao } } init { val db: QuoteRoomDatabase = QuoteRoomDatabase.getDatabase(application) mQuoteDao = db.QuoteDao() mAllQuotes = mQuoteDao.getAllQuotes() } }
ViewModel
The ViewModel is a class that provides data to the user interface and survives configuration changes. A ViewModel serves as a hub of communication between the Repository and the UI. A ViewModel can also be used to share data between fragments. The ViewModel is a component of the lifecycle library.
A ViewModel stores your app’s UI data in a lifecycle-aware manner that is resistant to configuration changes. Separating your app’s UI data from your Activity and Fragment classes allows you to better adhere to the single responsibility principle: your activities and fragments are in charge of drawing data to the screen, while your ViewModel is in charge of holding and processing all the data required for the UI.
Important Point:
Never pass context into ViewModel instances. In the ViewModel, do not store Activity, Fragment, or View instances or their Context. An Activity, for example, can be destroyed and recreated numerous times during the lifecycle of a ViewModel, such as when the device is rotated. If you keep a reference to the Activity in the ViewModel, you’ll end up with references to the destroyed activity. This is an example of a memory leak. Use AndroidViewModel instead of ViewModel if you require the application context. |
If you are interested in learning more about ViewModel, you can go through ViewModel and ViewModel Factory in Android with Examples here I have explained ViewModel and ViewModel Factory in detail with suitable Examples in Android, and several scenarios in which ViewModel can be useful. and I assure you that by the end, you will have a clear understanding of this commonly used technology.
Lifecycle-aware components
Lifecycles are associated with the majority of the app components defined in the Android framework. The operating system or framework code running in your process manages lifecycles. They are fundamental to how Android works, and your application must adhere to them. Failure to do so may result in memory leaks or even application crashes. Lifecycle-aware components include activities and fragments, and LiveData is also lifecycle aware.
Implementing the actions of the dependent components in the lifecycle methods of activities and fragments is a common pattern. For example, you could have a listener class that connects to a service when the activity begins and disconnects when it ends. You then override the onStart() and onStop() methods in the activity to start and stop the listener.
The android.arch.lifecycle package contains classes and interfaces that allow you to create lifecycle-aware components that automatically adjust their behavior based on an activity’s or fragment’s lifecycle state. That is, you can make any class aware of its lifecycle.
Use cases for lifecycle-aware components:
Lifecycle-aware components can make it much easier for you to manage lifecycles in a variety of cases. For example, you can use lifecycle-aware components to:
android architecture components, android architecture components, android architecture components, android architecture components, architecture components android, components of the android architecture, add architecture components android, android architecture components MVVM, android MVVM architecture components, android MVVM architecture components,architecture component in android
Stop and start video buffering.
Use lifecycle-aware components to begin video buffering as soon as possible, but delay playback until the app has fully loaded. You can also use lifecycle-aware components to stop buffering when your app is killed.
Connectivity to the network can be started and stopped.
Use lifecycle-aware components to enable live updating (streaming) of network data while an app is in the foreground, then pause the app when it moves to the background.
Animated drawable can be paused and resumed.
Use lifecycle-aware components to pause animated drawable while the app is in the background and resume them when the app returns to the foreground.
android architecture components, android architecture components, android architecture components, android architecture components, architecture components android, components of the android architecture, add architecture components android, android architecture components MVVM, android MVVM architecture components, android MVVM architecture components,architecture component in android
Paging library
The paging library allows your app to gradually load information from a data source as needed, without overloading the device or waiting too long for a large database query.
Many apps work with large amounts of data but only need to load and display a subset of that data at a time. An app may be capable of displaying thousands of items, but it may only require access to a few dozen of these items at a time. If the app is not carefully designed, it may request data that it does not require, putting a strain on the device and the network. If the data is stored or synchronized with a remote database, the app may become slow and consume the user’s data plan.
The paging library addresses issues with existing solutions. This library contains several classes that will help you request data as you need it. These classes also pair up with pre-existing Architecture Components such as Room.
We hope that this guide will assist you in understanding all about the concepts of LiveData and MutableLiveData in android. We have concentrated on making a basic, meaningful and easy-to -learn guide to the concepts of LiveData with suitable example. Still if you have any problems regarding it, please post them in the comments section, we will be glad to assist you.
Data Binding
The Data Binding Library is an Android Jetpack library that allows you to bind UI components in your XML layouts to data sources in your app using a declarative format rather than programmatically, reducing boilerplate code. It can be categorized into 2 types i.e.
1: One-Way binding
2: Two-Way binding
Benefits:
- Enhance the performance of your app.
- Assist in preventing memory leaks and null pointer exceptions.
- Remove UI framework calls from your activity’s code to make it more organized.
android architecture components, android architecture components, android architecture components, android architecture components, architecture components android, components of the android architecture, add architecture components android, android architecture components MVVM, android MVVM architecture components, android MVVM architecture components,architecture component in android
View Binding
View binding allows you to replace findViewById with generated binding objects in order to simplify code, eliminate bugs, and avoid all of the boilerplates of findViewById(). It is used to make working with views extremely simple and reduces a lot of boilerplate code, making it very simple to work with views and perform operations on them.
android architecture components,android architecture components,android architecture components
We hope that this guide will assist you in understanding all about the concepts of LiveData and MutableLiveData in android. We have concentrated on making a basic, meaningful and easy-to -learn guide to the concepts of LiveData with suitable example. Still if you have any problems regarding it, please post them in the comments section, we will be glad to assist you.
Advantages of View Binding
- ViewBinding supports both Java and Kotlin and is always null safe and type-safe.
- Gradle version 3.6 and higher introduce ViewBinding (which comes with the Android Studio 4.0, only gradle 3.6).
- ViewBinding also helps in the reduction of boilerplate code, hence reducing code repetition.
- Because it builds the binding class internally using the name of the same layout file, proper naming rules must be followed while using ViewBinding. It’s best to name the layout file in the snake case. For example, the ViewBinding creates the ActivityMainBinding(pascal case) file, which contains all the properties and instances of all the views in that layout.
- Moreover, whatever IDs of all elements are created inside the layout XML file, ViewBinding allows for better code compilation than the standard findViewById() approach.
If you are interested in learning Data binding and View Binding, you can go through Data Binding in Android with Example, and View Binding in Android with Example here I have explained Data Binding, One-way, and Two-way Data Binding, @BindingAdapter, View Binding in detail with suitable Examples in Android, and several scenarios in which data and view binding can be useful. and I assure you that by the end, you will have a clear understanding of this commonly used library.
android architecture components, android architecture components, android architecture components, android architecture components, architecture components android, components of the android architecture, add architecture components android, android architecture components MVVM, android MVVM architecture components, android MVVM architecture components,architecture component in android
- We hope that this guide will assist you in understanding all the concepts of Android Architecture Components. We have concentrated on making a basic, meaningful, and easy-to-learn guide to the concepts of Android Architecture Components with suitable examples. Still, if you have any problems regarding it, please post them in the comments section, we will be glad to assist you.
android architecture components,android architecture components,android architecture components,android architecture components
Pingback: Room Database Android Example- Building a Notes App