Unit 3 Understanding Activity and Fragment Lifecycle,
Android App Architecture,
View Model and View Model Factory classes,
Live data and Live data observers,
Data Binding with View Model and Live Data.
Overview of Room database,
Coroutines and Room,
Advanced Recycler View use cases
Unit-3:
Understanding Activity and Fragment Lifecycle
In Android development, activities and fragments are fundamental components that manage the
user interface. The lifecycle of an activity and a fragment refers to the various states they go
through during their existence.
Activity Lifecycle:
An activity represents a single screen in an Android app. It goes through several stages during its
lifecycle, such as:
onCreate(): Called when the activity is created. This is where initialization of components
happens.
onStart(): Called when the activity is becoming visible to the user.
onResume(): Called when the activity starts interacting with the user.
onPause(): Called when the activity is no longer in the foreground but still visible.
onStop(): Called when the activity is no longer visible to the user.
onRestart(): Called when the activity is brought back to the foreground after being stopped.
onDestroy(): Called when the activity is about to be destroyed.
Fragment Lifecycle:
A fragment is a portion of the user interface that can be reused across different activities. Its
lifecycle is similar to that of an activity but with some additional methods:
onAttach(): Called when the fragment is attached to an activity.
onCreate(): Called when the fragment is created.
onCreateView(): Used to inflate the fragment’s layout.
onActivityCreated(): Called when the activity's onCreate() method has been executed.
onStart(): Called when the fragment is visible to the user.
onResume(): Called when the fragment is interacting with the user.
onPause(): Called when the fragment is no longer in the foreground but still visible.
onStop(): Called when the fragment is no longer visible.
onDestroyView(): Called when the fragment's view is being destroyed.
onDetach(): Called when the fragment is detached from the activity.
Example:
Imagine a scenario where you open a social media app. The activity lifecycle manages when the
main screen appears, goes to the background, or gets destroyed. The fragment lifecycle would
manage things like when a comment section is shown or hidden on that screen.
Android App Architecture
Android App Architecture refers to the design principles, patterns, and components that guide
the development of a well-structured, maintainable, and scalable Android application.
Common Android Architectures:
MVC (Model-View-Controller):
o Model: Represents data and business logic.
o View: Represents the user interface.
o Controller: Acts as an intermediary between Model and View.
o Example: An old Android app that uses activities as controllers.
MVVM (Model-View-ViewModel):
o Model: Data layer (usually from a database or API).
o View: User interface.
o ViewModel: Stores UI-related data and handles business logic, allowing the View to
observe changes in the data.
o Example: Google’s Jetpack architecture uses MVVM to simplify UI updates.
MVP (Model-View-Presenter):
o Model: Data layer.
o View: User interface.
o Presenter: Acts as an intermediary between Model and View. It handles all the UI logic
and communicates with the Model.
o Example: A weather app that fetches weather data from an API and presents it to the
user.
Components of Android Architecture:
Activities and Fragments: Responsible for the UI and user interaction.
Services: Handle background tasks.
Broadcast Receivers: Listen for system or app events (e.g., incoming calls, Wi-Fi changes).
Content Providers: Manage shared data between apps.
ViewModel and ViewModelFactory Classes
The ViewModel and ViewModelFactory classes are part of Android’s architecture components
that help manage UI-related data in a lifecycle-conscious way.
ViewModel:
A ViewModel is designed to store and manage UI-related data in a lifecycle-conscious
way. It survives configuration changes, such as screen rotations, and prevents data loss.
The ViewModel holds the data that the UI (Activity or Fragment) needs to display. It
doesn’t directly manage the UI, but instead provides the data needed by the UI.
Example: If you are building an app that fetches data from an API, the ViewModel will
hold the API response data and handle any transformations. The activity or fragment will
observe changes to this data and update the UI accordingly.
ViewModelFactory:
A ViewModelFactory is used to create ViewModel instances that take parameters.
Sometimes you need to pass parameters (like a repository or use cases) into the
ViewModel, and the factory is responsible for creating the ViewModel with those
dependencies.
Example: If your ViewModel needs a reference to a repository, you would create a
ViewModelFactory to instantiate the ViewModel and inject the repository.
Summary:
Activity and Fragment Lifecycle: Refers to the states that an Activity or Fragment goes through
during its existence.
Android App Architecture: Refers to the design patterns and components that structure the app
in a scalable and maintainable way (e.g., MVC, MVVM).
ViewModel and ViewModelFactory: ViewModel holds UI-related data in a lifecycle-aware
Sure! Here’s an explanation of each heading in simple words with definitions, examples, and
types.
Live Data and Live Data Observers:
Live Data is an observable data holder in Android. It is part of the Android Architecture
Components and is lifecycle-aware, meaning it respects the activity or fragment lifecycle, and
only updates UI components when the activity or fragment is in an active state (e.g., when the
app is in the foreground). This prevents memory leaks and ensures the app is efficient.
Example: You can use LiveData to store a value like user data or a list of items.
Whenever the data changes, the UI is automatically updated.
Types:
o MutableLiveData: A subclass of LiveData that allows you to modify the stored
data.
o LiveData: A read-only version of LiveData that you can observe but not modify
directly.
Live Data Observers: Observers are responsible for listening to changes in LiveData.
When data changes, the observer automatically gets notified and can update the UI
accordingly.
Example: If the user’s profile information changes, the LiveData object stores the
updated data, and an observer in the UI (like an Activity or Fragment) gets notified to
update the UI.
Code Example:
LiveData<User> userLiveData = userViewModel.getUser(); // LiveData
holding User data
userLiveData.observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
// Update UI when user data changes
}
});
Data Binding with View Model and Live Data:
Data Binding is a technique in Android that allows you to bind UI components in your layouts
directly to data sources in your application. When using data binding with LiveData, the UI is
automatically updated whenever the data changes without having to manually handle it.
ViewModel: A ViewModel holds and manages UI-related data in a lifecycle-conscious
way. It acts as a bridge between the UI (Activity/Fragment) and the data (LiveData,
Room database, etc.). It ensures that the data survives configuration changes like screen
rotations.
LiveData and ViewModel: ViewModels expose LiveData objects to the UI
components. Since LiveData is observable, the UI can be updated automatically when
the data changes.
Data Binding: In your XML layout, you can bind the UI components (like TextViews,
Buttons, etc.) to LiveData from your ViewModel, and it will automatically update the UI
when the data changes.
Example: Suppose you have a User object stored in LiveData. You can bind the user’s
name to a TextView in the layout.
Code Example:
o XML Layout (activity_main.xml):
o <layout
xmlns:android="http://schemas.android.com/apk/res/android"
o xmlns:app="http://schemas.android.com/apk/res-auto"
o xmlns:tools="http://schemas.android.com/tools">
o
o <data>
o <variable
o name="user"
o type="com.example.app.User" />
o </data>
o
o <TextView
o android:id="@+id/textView"
o android:text="@{user.name}" />
o </layout>
o ViewModel:
o public class UserViewModel extends ViewModel {
o private LiveData<User> user;
o
o public LiveData<User> getUser() {
o if (user == null) {
o user = userRepository.getUser();
o }
o return user;
o }
o }
o Activity:
o UserViewModel userViewModel = new
ViewModelProvider(this).get(UserViewModel.class);
o ActivityMainBinding binding =
DataBindingUtil.setContentView(this, R.layout.activity_main);
o binding.setUser(userViewModel.getUser());
o binding.setLifecycleOwner(this);
Overview of Room Database:
Room Database is a persistence library provided by Android to manage local databases in an
efficient and easy-to-use way. It provides an abstraction layer over SQLite to simplify database
operations and reduce boilerplate code.
Room Components:
o Entity: A class that represents a table in the database. Each field in the class
corresponds to a column in the table.
o DAO (Data Access Object): Defines methods for accessing the data in the
database (like insert(), update(), delete(), and query()).
o Database: An abstract class annotated with @Database that provides the database
access methods and holds the entities.
Types of Room Database:
o Room Database (SQLite): Uses SQLite as the backend database. It simplifies
common SQLite tasks such as managing versions, schema migrations, etc.
o LiveData with Room: LiveData can be used with Room to observe changes in
the database in real-time. When the data in the database changes, the UI
automatically updates.
Example: Suppose you have a User table in the Room database, and you want to observe
changes in the database.
Code Example:
o Entity (User.java):
o @Entity(tableName = "users")
o public class User {
o @PrimaryKey
o public int id;
o public String name;
o public int age;
o }
o DAO (UserDao.java):
o @Dao
o public interface UserDao {
o @Insert
o void insert(User user);
o
o @Query("SELECT * FROM users WHERE id = :userId")
o LiveData<User> getUserById(int userId);
o }
o Database (AppDatabase.java):
o @Database(entities = {User.class}, version = 1)
o public abstract class AppDatabase extends RoomDatabase {
o public abstract UserDao userDao();
o }
o ViewModel:
o public class UserViewModel extends ViewModel {
o private LiveData<User> user;
o private UserDao userDao;
o
o public UserViewModel() {
o AppDatabase db = Room.databaseBuilder(context,
AppDatabase.class, "user-db").build();
o userDao = db.userDao();
o }
o
o public LiveData<User> getUser(int userId) {
o user = userDao.getUserById(userId);
o return user;
o }
o }
o Activity:
o UserViewModel userViewModel = new
ViewModelProvider(this).get(UserViewModel.class);
o userViewModel.getUser(1).observe(this, new Observer<User>() {
o @Override
o public void onChanged(User user) {
o // Update UI when user data changes
o }
o });
In summary, LiveData and LiveData Observers help in managing data in Android apps in a
lifecycle-aware way, Data Binding with ViewModel and LiveData allows automatic updates
of UI components without manual handling, and Room Database simplifies working with
SQLite databases while integrating seamlessly with LiveData.
Here’s a detailed explanation of the topics you mentioned:
Coroutines and Room
Coroutines: Coroutines are a feature in Kotlin that allow you to write asynchronous, non-
blocking code in a simpler and more understandable way. They help handle tasks that take time
to complete, such as downloading data from the internet or reading from a file, without blocking
the main thread (which could freeze the UI).
Key features:
o Suspending Functions: Functions that can be paused and resumed later.
o Coroutine Builders: Functions like launch, async, and runBlocking to start
coroutines.
o Dispatchers: Coroutines use different dispatchers (like Dispatchers.IO,
Dispatchers.Main) to specify which thread to run on.
Room: Room is a persistence library in Android that provides an abstraction layer over SQLite,
allowing for easy access to the database. It is used to store and retrieve data in an app in a
structured way. Room uses annotations to define entities (tables) and database access objects
(DAOs) for interacting with the database.
Key components:
o Entities: Represent tables in the database.
o DAO (Data Access Object): Interfaces for querying the database.
o Database: The main entry point to the app’s database.
Using Coroutines with Room: Coroutines are often used with Room to perform database
operations asynchronously. This ensures that the app's UI remains responsive, even during data
access operations like inserting, updating, or fetching data.
Example: Using Room with coroutines, you can insert data into a database like this:
@Insert
suspend fun insertUser(user: User)
The suspend keyword makes this function a suspending function, meaning it will run on
a background thread and will not block the UI thread.
Advanced RecyclerView Use Cases
RecyclerView: RecyclerView is a flexible and efficient view for displaying large data sets in
Android apps. It recycles views to improve performance and memory usage. It supports different
layout styles (e.g., LinearLayoutManager, GridLayoutManager) and can be customized for
complex layouts.
Advanced Use Cases: Here are some advanced use cases of RecyclerView that go beyond basic
usage:
1. Multiple View Types:
o RecyclerView supports displaying different types of items in the same list. For
example, you might have a list that includes both text items and image items. You
can implement getItemViewType to return different view types based on the
position of the item.
Example:
override fun getItemViewType(position: Int): Int {
return if (position % 2 == 0) TYPE_IMAGE else TYPE_TEXT
}
2. Item Animation: RecyclerView can be customized with item animations. You can define
animations for adding, removing, or changing items in the list to enhance the user
experience.
Example: Adding custom item animations:
val itemAnimator = DefaultItemAnimator()
recyclerView.itemAnimator = itemAnimator
3. Swipe-to-Dismiss: Implementing swipe-to-dismiss allows users to swipe an item to
delete or perform other actions. It is commonly used for actions like deleting or archiving
an item.
Example:
val itemTouchHelper = ItemTouchHelper(SwipeToDeleteCallback())
itemTouchHelper.attachToRecyclerView(recyclerView)
4. Endless Scrolling (Pagination): For large datasets, you can implement endless scrolling.
When the user reaches the end of the list, more data is fetched automatically and added to
the list.
Example:
o Use a RecyclerView.OnScrollListener to detect when the user is near the end
and trigger loading more data.
recyclerView.addOnScrollListener(object :
RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy:
Int) {
val layoutManager = recyclerView.layoutManager as
LinearLayoutManager
if (layoutManager.findLastVisibleItemPosition() ==
adapter.itemCount - 1) {
// Load more data
}
}
})
5. Drag-and-Drop: RecyclerView allows you to implement drag-and-drop functionality
where users can reorder items in the list by dragging them.
Example:
val itemTouchHelper = ItemTouchHelper(DragAndDropCallback())
itemTouchHelper.attachToRecyclerView(recyclerView)
6. View Holder Pattern: RecyclerView uses the ViewHolder pattern to improve
performance by reusing views that are no longer visible, reducing the need to inflate
views repeatedly. It is an efficient way to handle large data sets.
7. Nested RecyclerViews: RecyclerView can be used inside other RecyclerViews (nested
scrolling) to create complex layouts, like displaying categories of items and having their
own lists inside them.
Example: You can have a list of categories, and inside each category, there could be a
RecyclerView showing items for that category.
These advanced RecyclerView use cases help in optimizing the user experience, improving
performance, and enabling complex interactions with the list of data in Android apps.