Implementing MVVM Architecture in Android

The Model-View-ViewModel (MVVM) architecture is a popular design pattern for developing Android applications. It helps in separating the concerns of the application, making the code more modular, testable, and maintainable. This article will guide you through the steps of implementing MVVM architecture in an Android application.

1. Introduction to

MVVM

MVVM architecture consists of three main components:

  • Model: This represents the data layer of the application. It includes the data models and the business logic.
  • View: This represents the UI layer of the application. It displays the data and forwards user actions to the ViewModel.
  • ViewModel: This acts as a bridge between the Model and the View. It handles the presentation logic and prepares data for the View.

2. Setting Up the

Project

To get started with MVVM, create a new Android project in Android Studio. Make sure to include the necessary dependencies in your build.gradle file:

Gradle build.gradle
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" implementation "androidx.room:room-runtime:2.3.0" kapt "androidx.room:room-compiler:2.3.0"

3. Creating the Model

The Model represents the data and business logic of the application. In this example, we'll use Room to create a simple database for storing user information. First, define the data entity:

Kotlin User.kt
import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "users") data class User( @PrimaryKey(autoGenerate = true) val id: Int, val name: String, val email: String )

Next, create the DAO (Data Access Object) interface:

Kotlin UserDao.kt
import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.Query @Dao interface UserDao { @Insert suspend fun insert(user: User) @Query("SELECT * FROM users") fun getAllUsers(): LiveData> }

Finally, create the database class:

Kotlin AppDatabase.kt
import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase @Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao companion object { @Volatile private var instance: AppDatabase? = null fun getDatabase(context: Context): AppDatabase = instance ?: synchronized(this) { instance ?: buildDatabase(context).also { instance = it } } private fun buildDatabase(context: Context) = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "app_database") .build() } }

4. Creating the

ViewModel

The ViewModel handles the presentation logic and prepares data for the View. Create a ViewModel class to manage user data:

Kotlin UserViewModel.kt
import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch class UserViewModel(application: Application) : AndroidViewModel(application) { private val userDao = AppDatabase.getDatabase(application).userDao() val allUsers: LiveData> = userDao.getAllUsers() fun insert(user: User) { viewModelScope.launch { userDao.insert(user) } } }

5. Creating the View

The View displays the data and forwards user actions to the ViewModel. In this example, we'll create a simple activity to display a list of users and a form to add new users.

5.1 Layout File

Create a layout file for the activity:

XML activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="viewModel" type="com.example.app.UserViewModel" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/nameEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Name" /><EditText android:id="@+id/nameEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Name" android:layout_below="@id/nameEditText" /> <EditText android:id="@+id/emailEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Email" android:layout_below="@id/nameEditText" android:layout_marginTop="10dp" /> <Button android:id="@+id/addButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add User" android:layout_below="@id/emailEditText" android:layout_marginTop="10dp" android:onClick="@{() -> viewModel.insert(new User(0, nameEditText.text.toString(), emailEditText.text.toString()))}" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/addButton" android:layout_marginTop="20dp" /> </RelativeLayout> </layout>

5.2 Activity Class

Create the MainActivity class to bind the ViewModel to the layout and handle user interactions:

Kotlin MainActivity.kt
import android.os.Bundle import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.example.app.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private val userViewModel: UserViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) val adapter = UserAdapter() binding.recyclerView.adapter = adapter binding.recyclerView.layoutManager = LinearLayoutManager(this) userViewModel.allUsers.observe(this, Observer { users -> users?.let { adapter.submitList(it) } }) binding.addButton.setOnClickListener { val name = binding.nameEditText.text.toString() val email = binding.emailEditText.text.toString() userViewModel.insert(User(0, name, email)) } } }

6. Creating the

Adapter

To display the list of users in a RecyclerView, create an adapter:

Kotlin UserAdapter.kt
import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.example.app.databinding.UserItemBinding class UserAdapter : ListAdapter(UserDiffCallback()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { val binding = UserItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) return UserViewHolder(binding) } override fun onBindViewHolder(holder: UserViewHolder, position: Int) { val user = getItem(position) holder.bind(user) } class UserViewHolder(private val binding: UserItemBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(user: User) { binding.userName.text = user.name binding.userEmail.text = user.email } } class UserDiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: User, newItem: User): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: User, newItem: User): Boolean { return oldItem == newItem } } }

7. Conclusion

Implementing MVVM architecture in your Android application can greatly improve the separation of concerns and make your code more modular and testable. By following the steps outlined in this article, you can set up MVVM architecture, create a simple database using Room, and connect the data layer with the UI layer using ViewModel and LiveData. This approach will help you build scalable and maintainable applications.

For more information and best practices, refer to the official Android Jetpack Guide.

Post a Comment

Previous Post Next Post