Kotlin-Mvvm-DaggerHilt-Preferences Data Store-Example
Step 1:
Open build.gradle(:Project) and add following dependency and rebuild the project.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.4"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.40.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Step 2:
Open build.gradle(:app) and add following dependency and rebuild the project.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk 31
defaultConfig {
applicationId "in.kotlinkatta.kotlinkattademo"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
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'
}
buildFeatures{
dataBinding true;
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//kotlin Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
//room
implementation "androidx.room:room-ktx:2.4.1"
implementation "androidx.room:room-runtime:2.4.1"
kapt "androidx.room:room-compiler:2.4.1"
//multidex
implementation 'androidx.multidex:multidex:2.0.1'
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
// view model ktx
implementation 'androidx.activity:activity-ktx:1.4.0'
//hilt viewmodel
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'
kapt("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.3.0")
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//moshi
implementation("com.squareup.moshi:moshi-kotlin:1.12.0")
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
//SharedPreferences
implementation("androidx.datastore:datastore:1.0.0")
implementation("androidx.datastore:datastore-preferences:1.0.0")
//DaggerHilt
implementation 'com.google.dagger:hilt-android:2.40.5'
kapt 'com.google.dagger:hilt-compiler:2.40.5'
}
// Allow references to generated code
kapt {
correctErrorTypes = true
}
Step 3:
Open gradle.properties and add following code and rebuild the project.
kapt.use.worker.api=false
Step 4:
Open AndroidManifest.xml and add following dependency and rebuild the project.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="in.kotlinkatta.kotlinkattademo">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".container.BaseApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.KotlinKattaDemo">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
App Flow Image:
Step 5:
Create new class BaseApp.kt and add following code.
package `in`.kotlinkatta.kotlinkattademo.container
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class BaseApp : Application() {}
Step 6:
Create new class AppDataStore.kt and add following code.
package `in`.kotlinkatta.kotlinkattademo.datastore
import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
import javax.inject.Inject
class AppDataStore @Inject constructor(@ApplicationContext val context: Context) {
companion object {
private val Context.dataStore by preferencesDataStore(name = "kotlinkatta")
}
object PreferencesKey {
val user_id = stringPreferencesKey("user_id")
val user_name = stringPreferencesKey("user_name")
val user_email = stringPreferencesKey("user_email")
}
suspend fun saveToLocal_AllData(
user_id: String,
user_name: String,
user_email: String
) {
context.dataStore.edit { preference ->
preference[PreferencesKey.user_id] = user_id
preference[PreferencesKey.user_name] = user_name
preference[PreferencesKey.user_email] = user_email
}
}
suspend fun saveToLocal_user_id(user_id: String) {
context.dataStore.edit { preference ->
preference[PreferencesKey.user_id] = user_id
}
}
suspend fun saveToLocal_user_name(user_name: String) {
context.dataStore.edit { preference ->
preference[PreferencesKey.user_name] = user_name
}
}
suspend fun saveToLocal_user_email(user_email: String) {
context.dataStore.edit { preference ->
preference[PreferencesKey.user_email] = user_email
}
}
val readFromLocal_user_id: Flow<String> = context.dataStore.data
.catch { it ->
if (this is Exception) {
emit(emptyPreferences())
}
}.map { preference ->
val user_id = preference[PreferencesKey.user_id] ?: ""
user_id
}
val readFromLocal_user_name: Flow<String> = context.dataStore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}.map { preference ->
val user_name = preference[PreferencesKey.user_name] ?: ""
user_name
}
val readFromLocal_user_email: Flow<String> = context.dataStore.data
.catch { it ->
if (this is Exception) {
emit(emptyPreferences())
}
}.map { preference ->
val user_email = preference[PreferencesKey.user_email] ?: ""
user_email
}
suspend fun deleteAllDataStoreData() {
context.dataStore.edit { preference ->
preference.clear()
}
}
}
Step 7:
Create new class AppDataStoreViewModel.kt and add following code.
package `in`.kotlinkatta.kotlinkattademo.uiviewmodel
import `in`.kotlinkatta.kotlinkattademo.datastore.AppDataStore
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AppDataStoreViewModel
@Inject
constructor(private val appDataStore: AppDataStore) : ViewModel() {
fun saveToLocal_AllData(user_id: String, user_name: String, user_email: String) =
viewModelScope.launch(Dispatchers.IO) {
appDataStore.saveToLocal_AllData(user_id, user_name, user_email)
}
fun saveToLocal_user_id(user_id: String) =
viewModelScope.launch(Dispatchers.IO) {
appDataStore.saveToLocal_user_id(user_id)
}
fun saveToLocal_user_name(user_name: String) =
viewModelScope.launch(Dispatchers.IO) {
appDataStore.saveToLocal_user_name(user_name)
}
fun saveToLocal_user_email(user_email: String) =
viewModelScope.launch(Dispatchers.IO) {
appDataStore.saveToLocal_user_email(user_email)
}
val readFromLocal_user_id = appDataStore.readFromLocal_user_id
val readFromLocal_user_name = appDataStore.readFromLocal_user_name
val readFromLocal_user_email = appDataStore.readFromLocal_user_email
fun deleteAllDataStoreData() =
viewModelScope.launch(Dispatchers.IO) {
appDataStore.deleteAllDataStoreData()
}
}
Step 8:
Open layout xml file activity_main.xml and add following code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="15dp"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Preference Data Stored"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="30dp"/>
<EditText
android:id="@+id/edtuserid"
android:hint="Enter User Id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_margin="5dp"
android:inputType="number"
android:background="#E7E7E7"/>
<EditText
android:id="@+id/edtusername"
android:hint="Enter User Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_margin="5dp"
android:background="#E7E7E7"/>
<EditText
android:id="@+id/edtuseremail"
android:hint="Enter User Email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_margin="5dp"
android:background="#E7E7E7"/>
<LinearLayout
android:layout_marginTop="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/btnsave"
android:layout_margin="5dp"
android:layout_weight="1"
android:text="Save"
android:textAllCaps="false"
android:background="#FF03DAC5"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btnview"
android:layout_margin="5dp"
android:layout_weight="1"
android:textAllCaps="false"
android:text="View"
android:background="#FF03DAC5"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btnclear"
android:layout_margin="5dp"
android:layout_weight="1"
android:textAllCaps="false"
android:text="Clear"
android:background="#FF03DAC5"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="@+id/txtUserId"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"/>
<TextView
android:id="@+id/txtUserName"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"/>
<TextView
android:id="@+id/txtUserEmail"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"/>
</LinearLayout>
Step 9:
Open Activity class file MainActivity.kt and add following code.
package `in`.kotlinkatta.kotlinkattademo
import `in`.kotlinkatta.kotlinkattademo.databinding.ActivityMainBinding
import `in`.kotlinkatta.kotlinkattademo.uiviewmodel.AppDataStoreViewModel
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
@AndroidEntryPoint
public class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val appDataStoreViewModel: AppDataStoreViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
funAllBtnClick()
funDisplayData()
}
private fun funAllBtnClick() {
binding.btnsave.setOnClickListener {
val str_user_id = binding.edtuserid.text.toString()
val str_name = binding.edtusername.text.toString()
val str_email = binding.edtuseremail.text.toString()
if (str_user_id.equals("") || str_name.equals("") || str_email.equals("")) {
Toast.makeText(this, "Please Enter Details.", Toast.LENGTH_SHORT).show()
} else {
appDataStoreViewModel.saveToLocal_AllData(str_user_id, str_name, str_email)
Toast.makeText(this, "Data Saved Successfully.", Toast.LENGTH_SHORT).show()
}
binding.edtuserid.text.clear()
binding.edtusername.text.clear()
binding.edtuseremail.text.clear()
}
binding.btnview.setOnClickListener {
funDisplayData()
}
binding.btnclear.setOnClickListener {
appDataStoreViewModel.deleteAllDataStoreData()
}
}
private fun funDisplayData() {
lifecycleScope.launchWhenStarted {
appDataStoreViewModel.readFromLocal_user_id.collect { strUserId ->
binding.txtUserId.text = "UserId : " + strUserId
}
}
lifecycleScope.launchWhenStarted {
appDataStoreViewModel.readFromLocal_user_name.collect { strUserName ->
binding.txtUserName.text = "UserName : " + strUserName
}
}
lifecycleScope.launchWhenStarted {
appDataStoreViewModel.readFromLocal_user_email.collect { strUserEmail ->
binding.txtUserEmail.text = "UserEmail : " + strUserEmail
}
}
}
}
Output :
Comments
Post a Comment