Android architecture is defined as the, A Guide to android app architecture with libraries for a different task, it helps us to create an app that is robust, testable, maintainable, and has less boilerplate code,
Architecture component is part of Android jetpack
Android jetpack is collection of android software component like data binding, lifecycles, livedata, app component, etc, it makes android development easy because it gives proper architecture to develop an application which has minimal boilerplate code
Android Architecture components
- DataBinding
- LifeCycleAwareComponent
- LiveData
- Navigation
- Paging
- Room
- ViewModel
- WorkManager
LifeCycleAwareComponent :—-
Q-What are LifeCycleAware components?
-Activity/Fragment is lifecycleowner
Activity —– lifecycle —– LifeCycleOwner
LifeCycle class uses event and state to determine the lifecycle of the lifecycle owner, Each event in the lifecycle is related to the particular state
LifeCycleObserver:——-
Which observe the activity and keep track of its lifecycle thus lifecycle observer performs Action and action depend on lifecycleowner lifecycle event
Dependency you have to include in your project—
implementation “android.arch.lifecycle:extensions:$lifecycle_version” |
annotationProcessor “android.arch.lifecycle:compiler:$lifecycle_version” |
-> LifeCycle class hold info about lifecycle of LifeCycleOwner
LifeCycle object uses following enumeration to track LifeCycle status
- Event
- State
Lifecycle Owner Provides Lifecycle status to LifecycleAware component
LifeCycleObserver registers Lifecycle status to respond and perform and perform the action
// LifecycleOwner
public class MainActivity extends AppCompatActivity { private String TAG = this.getClass().getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getLifecycle().addObserver(new MainActivityObserver()); } @Override protected void onStart() { super.onStart(); Log.i(TAG, "owner onstart"); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "owner onResume"); } @Override protected void onPause() { super.onPause(); Log.i(TAG, "owner onPause"); } @Override protected void onStop() { super.onStop(); Log.i(TAG, "owner onStop"); } @Override protected void onDestroy() { super.onDestroy(); Log.i(TAG, "Observer Removed"); getLifecycle().removeObserver(new MainActivityObserver()); } } public class MainActivityObserver implements LifecycleObserver { private String TAG = this.getClass().getSimpleName(); @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public void onCreateEvent() { Log.i(TAG, "ON_CREATE Event"); } @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStartEvent() { Log.i(TAG, "ON_START event"); } @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void onResumeEvent() { Log.i(TAG, "ON_RESUME event"); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void onPauseEvent() { Log.i(TAG, "ON_PAUSE event"); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStopEvent() { Log.i(TAG, "ON_STOP event"); } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void onDestroyEvent() { Log.i(TAG, "ON_DESTROY event"); } }
Note:–Lifecycle observer observe the lifecycle event of lifecycle owner(Activity/Fragment)
During the creation of activity owner lifecycle event execute first, during destruction action the lifecycle observer execute first
———————————————-ViewModel and LiveData—————————————–
The dependency you have to implement in your project
//ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // LiveData implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version" // Saved state module for ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" --->View model is not same as onSaveInstanceState() --->View model uses for large data such as bitmap or user list --->View model store and manage UI related data ---> View model Destroy only if the owner activity is completely destroyed, in onCleared() --->View model Communication layer between Database and UI
Q – why do we need a view model?
when you start developing an application the most common thing you need to handle is configuration changes
like:- when we rotate the device the activity is reloaded thus the old data is loss and new one is created, we need to keep our data safe to do that we use viewmodel, then the view model provides the data after changes of configuration
-> Action perform during changes of configuration
during the change of configuration (Activity/Fragment destroy) the data goes from activity to model and after recreating of activity/fragment the view model provides the data to UI, Science the activity is created we linked it to view model, using view model provider
public class MainActivity extends AppCompatActivity { private String TAG = this.getClass().getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); TextView mTextView = findViewById(R.id.tvNumber); MainActivityViewModel model = ViewModelProviders.of(this).get(MainActivityViewModel.class); String myRandomNumber = model.getNumber(); mTextView.setText(myRandomNumber); Log.i(TAG, "Random Number Set"); } }
ViewModel Class ——–
public class MainActivityViewModel extends ViewModel { private String TAG = this.getClass().getSimpleName(); private String myRandomNumber; public String getNumber() { Log.i(TAG, "Get number"); if (myRandomNumber == null) { createNumber(); } return myRandomNumber; } private void createNumber() { Log.i(TAG, "Create new number"); Random random = new Random(); myRandomNumber = "Number: " + (random.nextInt(10 - 1) + 1); } @Override protected void onCleared() { super.onCleared(); Log.i(TAG, "ViewModel Destroyed"); } }-
Live data:—-
traditional approach —
-> using interface
-> Using Event Bus Such as Otto
-> Live data is the best way to manage the runtime changes of data and reflect that changes to UI (recommended by Google)
Note:- MutableLive Data extends LiveData
Q-Why we use Mutable live data?
Ans- Mutable live data have a public getter and setter method, so it will easy to manipulate the data
-> Live data is an Observable data holder class that keeps data and allow data to be observed
Note -> Observe LiveData from app components onCreate() method
Benefits of LiveData:–
—>it keeps the UI updated in case of any changes
—>it automatically destroyed when associated LifeCycleOwner is destroyed
—>There is no crashes due to stopped activities
—>it can be shared by multiple resources
—>It works efficiently when you used it with the view model
Note:- when you move from one activity to another activity the first activity observer stop observing the data
RoomDatabase:-
//room implementation "androidx.room:room-runtime:2.2.5"
SQLite Vs Room
SQLite:—
-> It Deals with raw queries
-> There is no Compile time verification of raw SQL queries
-> Lots of boilercode to convert between SQL queries and java data objects
-> SQLite API is low-level, so more time more effectively to build apps
Room:–
->it has No raw queries
-> during Compile time it checks SQLite statements
-> it Maps database object and java objects without boilerplate code
-> using of the room is efficient When we used it with ViewModel and live data
Q-What is Room?
Room database contains Database layer on top of SQLite, it provides an abstraction layer over SQLite to allow fluent database access, it works on object Relation Mapping library(ORM)
Benefits: – easy caching of relevant pieces of database
Components of Room:-
->Entities
– it defines the schema of the database table
– Annotated with @Entity
->DAO
– it contains a method to access the database
– Annotated with @Dao
->Database
-database holder class
-Annotated with @Database
->Annotating the Java class with @Entity, room generate all the necessary code to create an SQLite table for this object,
->we can turn an integer member variable into an auto-incrementing primary key, By Columns for all, its fields. With @PrimaryKey and autoGenerate = true, from which we can use to uniquely identify each row in the table.
->We can also specify the tableName if it should be different than the class name.
@Entity(tableName = "users") public class User { @PrimaryKey public int id; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName; }
@Entity:-generate all necessary code to create an SQLite table for this object as well as column for all this field
UserList.java :------ @Entity(tableName = "user_entity") public class User{ @PrimaryKey(autoGenerate = true) public int id; public String name; public Note(String name, String description, int jobNo) { this.name= name; this.description = description; this.jobNo= jobNo; } public String description; public int jobNo; }
DAO:-
->We define all database operation in DAO
->we declare all operational method without method body, annotated with @insert,@Updates,@Delete
->For generic, we declare it with @Query, we can pass an SQLite query with from it
->The RoomDatabase works efficiently with live data because our activity or fragment gets notified as soon as a row in the queried database table changes.
Note: Room does not allow data operation on the main thread
UserDao.java :——
@Dao
public interface UserDao { @Insert void insert(User); @Update void update(User details); //we can also pass multiple argument @Delete void delete(User user); @Query("DELETE FROM user_entity") void deleteAllUser(); @Query("SELECT *FROM user_entity ORDER BY priority DESC") LiveData<List<User>>getAllUser(); }
RoomDatabase:-
-> RoomDatabase is an abstract class that acts as a bridge and connects the entities to their corresponding DAO. Just as in an SQLiteOpenHelper.
->we have to define a version number and a migration strategy. With fallback To Destructive Migration, we can let Room recreate our database if we increase the version number.