In this android example tutorial, we will see What is ViewModel and how to implement viewmodel pattern in Android Login Screen Kotlin code.
What is ViewModel?
In Android, the ViewModel class is intended to store and handle UI-related data in a lifecycle-aware manner. The ViewModel class enables data to persist via configuration changes such as screen rotations.
ViewModel Implementation in Login Screen:
Step 1: Create a new Project in android studio.
Go to File > New > New Project > Empty Activity > Next > Enter Name > Select Language Kotlin > Finish |
Step 2: Open build.gradle(app) file and add the following code
Add ViewModel and LiveData Lifecycle dependency inside dependencies..
// ViewModel |
Add the kotlin-kapt inside plugins
id 'kotlin-kapt' |
Enable the DataBinding inside android...
buildFeatures{ |
Step 3: Create LoginUser Model
Create a new kotlin file (LoginUser.kt) and add the following code:
class User(private var email: String, private var password: String) : BaseObservable() { fun getPassword(): String { fun getEmail(): String { fun setEmail(email: String) { fun setPassword(password: String) { } |
Step 4: Create a Interface
Create a new kotlin file (LoginResultCallBacks.kt) which has two function onSuccess and onError be like:
interface LoginResultCallBacks { |
Step 5: Implement ViewModel
Create a new kotlin file (LoginViewModel.kt) and add the following code:
class LoginViewModel(private val listener: LoginResultCallBacks) : ViewModel() { init { val emailTextWatcher: TextWatcher override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } } fun onLoginClicked(v: View) { } |
TextWatcher: The Android Developer API has a useful class called TextWatcher. It can be used to keep an eye on an input text field and rapidly update data in other views. It can be handy for immediately counting the number of characters input in the text field and measuring password strength when entering, among other things.
Methods of TextWatcher
abstract void |
afterTextChanged(Editable s) |
abstract void |
beforeTextChanged(CharSequence s, int start, int count, int after) |
abstract void |
onTextChanged(CharSequence s, int start, int before, int count) |
Create a new file of Kotlin (LoginViewModelFactory.kt) and add the following code:
We need to pass some input data to the constructor of the viewModel , we need to create a factory class for viewModel.
class LoginViewModelFactory (private val listener: LoginResultCallBacks):ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { |
Step 6: Open activity_main.xml file and add the following xml code.
<?xml version="1.0" encoding="utf-8"?> <data> <variable <LinearLayout <TextView <EditText <EditText <Button |
Above layout file gives you output as below:
Step 7: Go to MainActivity.kt file
Bind the view with activity, add the following code below setContentView(R.layout.activity_main).
val activityMainBinding = DataBindingUtil.setContentView activityMainBinding.viewModel = ViewModelProviders.of(this,LoginViewModelFactory(this)).get(LoginViewModel::class.java) |
Implement the LoginResultCallBacks Interface in MainActivity.kt file
class MainActivity : AppCompatActivity(), LoginResultCallBacks { |
Implement the methods of LoginResultCallBacks onSuccess() and onError()
override fun onSuccess(message: String) { override fun onError(message: String) { |
Final Code of MainActivity.kt file,
class MainActivity : AppCompatActivity(), LoginResultCallBacks { override fun onError(message: String) { override fun onCreate(savedInstanceState: Bundle?) { val activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main) |
Step 8: Now run the app in your emulator or real device, you will get the given output:
When the field is empty:
When we typed wrong email address:
When we entered password value less than 6 digits:
When everthing is Okay then it shows you success message:
Complete Source Code of Login with ViewModel Example:
activity_main.xml file
<?xml version="1.0" encoding="utf-8"?> <data> <variable <LinearLayout <TextView <EditText <EditText <Button |
MainActivity.kt file
import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity(), LoginResultCallBacks { override fun onError(message: String) { override fun onCreate(savedInstanceState: Bundle?) { val activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main) |
LoginUser.kt file
import android.text.TextUtils
fun getPassword(): String { fun getEmail(): String { fun setEmail(email: String) { fun setPassword(password: String) { } |
LoginResultCallBacks.kt file
interface LoginResultCallBacks { |
LoginViewModel.kt file
import android.text.Editable class LoginViewModel(private val listener: LoginResultCallBacks) : ViewModel() { init { val emailTextWatcher: TextWatcher override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } } fun onLoginClicked(v: View) { } |
LoginViewModelFactory.kt file
import androidx.lifecycle.ViewModel class LoginViewModelFactory (private val listener: LoginResultCallBacks):ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { |
build.gradle(app) file
plugins { } android { defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildFeatures{ dependencies { implementation 'androidx.core:core-ktx:1.7.0' |
Conclusion: In this example we have covered what is Android Jetpack ViewModel and how to implement Login Screen with ViewModel in Android Studio using Kotlin Language.
<?xml version="1.0" encoding="utf-8"?>
Above layout file gives you output as below:
Step 7: Go to MainActivity.kt file
Bind the view with activity, add the following code below setContentView(R.layout.activity_main).
val activityMainBinding = DataBindingUtil.setContentView activityMainBinding.viewModel = ViewModelProviders.of(this,LoginViewModelFactory(this)).get(LoginViewModel::class.java) |
Implement the LoginResultCallBacks Interface in MainActivity.kt file
class MainActivity : AppCompatActivity(), LoginResultCallBacks { |
Implement the methods of LoginResultCallBacks onSuccess() and onError()
override fun onSuccess(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } override fun onError(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } |
Final Code of MainActivity.kt file,
class MainActivity : AppCompatActivity(), LoginResultCallBacks { override fun onSuccess(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } override fun onError(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main) activityMainBinding.viewModel = ViewModelProviders.of(this, LoginViewModelFactory(this)) .get(LoginViewModel::class.java) } } |
Step 8: Now run the app in your emulator or real device, you will get the given output:
When the field is empty:
When we typed wrong email address:
When we entered password value less than 6 digits:
When everthing is Okay then it shows you success message:
Complete Source Code of Login with ViewModel Example:
activity_main.xml file
<?xml version="1.0" encoding="utf-8"?> <data> <variable <LinearLayout <TextView <EditText android:id="@+id/etPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:hint="Enter Password" app:addTextChangedListener="@{viewModel.passwordTextWatcher}"></EditText> <Button android:id="@+id/loginBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:onClick="@{viewModel::onLoginClicked}" android:text="Login"></Button> </LinearLayout> </layout> |
MainActivity.kt file
import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.nishajain.loginregisterwithviewmodel.databinding.ActivityMainBinding import android.widget.Toast import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProviders class MainActivity : AppCompatActivity(), LoginResultCallBacks { override fun onSuccess(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } override fun onError(message: String) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main) activityMainBinding.viewModel = ViewModelProviders.of(this, LoginViewModelFactory(this)) .get(LoginViewModel::class.java) } } |
LoginUser.kt file
import android.text.TextUtils import android.util.Patterns import androidx.databinding.BaseObservable class LoginUser(private var email: String, private var password: String) : BaseObservable() { fun isDataValid(): Int { if (TextUtils.isEmpty(getEmail())) return 0 else if (!Patterns.EMAIL_ADDRESS.matcher(getEmail()).matches()) return 1 else if (getPassword().length < 6) return 2 else return -1 } fun getPassword(): String { return password } fun getEmail(): String { return email } fun setEmail(email: String) { this.email = email } fun setPassword(password: String) { this.password = password } } |
LoginResultCallBacks.kt file
interface LoginResultCallBacks { fun onSuccess(message: String) fun onError(message: String) } |
LoginViewModel.kt file
import android.text.Editable import android.text.TextWatcher import android.view.View import androidx.lifecycle.ViewModel class LoginViewModel(private val listener: LoginResultCallBacks) : ViewModel() { private val user: LoginUser init { this.user = LoginUser("", "") } val emailTextWatcher: TextWatcher get() = object : TextWatcher { override fun afterTextChanged(s: Editable?) { user.setEmail(s.toString()) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { // Code what you want to show before edit the email box } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { // Code what you want to show on text Changed in email box } } //create function to set Password after user finish enter text val passwordTextWatcher: TextWatcher get() = object : TextWatcher { override fun afterTextChanged(s: Editable?) { user.setPassword(s.toString()) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { // Code what you want to show before edit the password box } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { // Code what you want to show on text Changed in password box } } fun onLoginClicked(v: View) { val loginCode: Int = user.isDataValid() if (loginCode == 0) listener.onError("Enter Email ID") else if (loginCode == 1) listener.onError("Invalid Email") else if (loginCode == 2) listener.onError("Password must be greater than 5") else listener.onSuccess("Success") } } |
LoginViewModelFactory.kt file
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider class LoginViewModelFactory (private val listener: LoginResultCallBacks):ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { return LoginViewModel(listener) as T } } |
build.gradle(app) file
plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' } android { compileSdk 31 defaultConfig { applicationId "com.nishajain.loginregisterwithviewmodel" minSdk 21 targetSdk 31 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures{ dataBinding true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.2' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" // LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0" } |
Conclusion: In this example we have covered what is Android Jetpack ViewModel and how to implement Login Screen with ViewModel in Android Studio using Kotlin Language.
-->
Article Contributed By :
|
|
|
|
2165 Views |