Part 2 : Implementing Preferences Datastore + Dependency Injection + Onboarding ViewModel

Mohit Damke
4 min readJul 4, 2024

--

Here we will implement Dagger Hilt for dependency injection and implement Preferences Datastore for storing data in database

Implement Preferences Datastore

  • First read this article on the Preferences Datastore
  • We are using Preferences Datastore because we have small amount of data to be visible

First we have to create LocalUserManager in the Manager Package inside Domain Package

package com.example.newsapp.domain.manager

import kotlinx.coroutines.flow.Flow

interface LocalUserManager {

suspend fun saveAppEntry()

fun readAppEntry(): Flow<Boolean>
}
  • Here we have created suspend function for Save App Entry and another function for read app entry which return type in flow boolean.

We have to create LocalUserManagerImpl in the Manager Package inside Data Package

package com.example.newsapp.data.manager

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import com.example.newsapp.domain.manager.LocalUserManager
import com.example.newsapp.util.Constants
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class LocalUserManagerImpl(
private val context: Context
) : LocalUserManager {
override suspend fun saveAppEntry() {
context.dataStore.edit { setting ->
setting[PreferencesKeys.APP_ENTRY] = true
}
}

override fun readAppEntry(): Flow<Boolean> {
return context.dataStore.data.map { preferences ->
preferences[PreferencesKeys.APP_ENTRY] ?: false
}
}
}
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = Constants.USER_SETTINGS)

private object PreferencesKeys {
val APP_ENTRY = booleanPreferencesKey(name = Constants.APP_ENTRY)
}
  • Here we have created the Local User Manager Implementation where we have implemented the Preferences datastore
  • NOTE : I have save the App Entry & NAME OF Database in the other object file below
object Constants {
const val USER_SETTINGS = "userSettings"
const val APP_ENTRY = "appEntry"
const val API_KEY = //TODO: YOUR API KEY
const val BASE_URL = "https://newsapi.org/v2/"
const val NEW_DATABASE = "news_db"
}

Make Use Cases

  • We have to implement its use cases
class SaveAppEntry(
private val localUserManager : LocalUserManager
) {

suspend operator fun invoke(){
localUserManager.saveAppEntry()
}
}
class ReadAppEntry(
private val localUserManager : LocalUserManager
) {

operator fun invoke() : Flow<Boolean> {
return localUserManager.readAppEntry()
}
}
  • And make another Data Class which contains both
data class AppEntryUseCases(
val readAppEntry: ReadAppEntry,
val saveAppEntry: SaveAppEntry
)

Dependency Injection

  • Here are the two article which tells about Dependency Injection just read it

Now We have to implement Dagger Hilt for Dependency Injection

  • Create di Package for Dependency Injection
  • Create new Object file as AppModule
@Module
@InstallIn(SingletonComponent::class)
object AppModule {

@Provides
@Singleton
fun provideLocalUserManager(
application: Application
): LocalUserManager = LocalUserManagerImpl(application)


@Provides
@Singleton
fun provideAppEntryUseCases(
localUserManger: LocalUserManager
): AppEntryUseCases = AppEntryUseCases(
readAppEntry = ReadAppEntry(localUserManger),
saveAppEntry = SaveAppEntry(localUserManger)
)
  • Here we need to specify the LocalUserManager and App Entry UseCases
  • Thus we implement dagger hilt

OnBoarding ViewModel

  • Thus we have to create the onboarding viewmodel so that we have to create a logic for the get started button.
  • And also define the functionality for the app start.
  • If the user have clicked on the app get started button once after downloading and opening of app then he will be not able to see the onboarding screen again after closing and opening of an app and he will always land on Home Screen (News Feed Screen).

Create OnBoarding ViewModel

package com.example.newsapp.presentation.onboarding

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.newsapp.domain.usecases.app_entry.AppEntryUseCases
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class OnBoardingViewModel @Inject constructor(
private val appEntryUseCases: AppEntryUseCases
): ViewModel() {

fun onEvent(event: OnBoardingEvent) {
when(event) {
is OnBoardingEvent.SaveAppEntry -> {
saveAppEntry()
}
}
}

private fun saveAppEntry() {
viewModelScope.launch {
appEntryUseCases.saveAppEntry()
}
}
}
  • Inject the constructor as private val appEntryUseCases form AppEntryUseCases.
  • Here we have just created onEvent function and added constructor event from onBoardingEvent.
  • Add Event on the onBoardingScreen
fun OnBoardingScreen(
modifier: Modifier = Modifier, event: (OnBoardingEvent) -> Unit
)
NewsButton(text = buttonState.value[1], onClick = {
scope.launch {
if (pagerState.currentPage == 2) {
event(OnBoardingEvent.SaveAppEntry)
}
  • Add the if Condition as the event OnBoardingEvent.SaveAppEntry
  • No the Get Started Button will click and this will help in the saving user information about clicking on the button
  • Then user will land on the home page directly
  • So now we have successfully implemented the onboarding screen in our app.

If you have not read Part 1 of the series the here is the link below

You can visit the introduction article for the news app with the link below

You can add 50 clap by just pressing on clap icon

Visit my GitHub Repository : https://github.com/mohitdamke/NewsApp

Make sure to follow me on
Link-tree :
https://linktr.ee/MohitDamke01
LinkedIn :
https://www.linkedin.com/in/mohitdamke01

--

--

Mohit Damke

Android Developer | Kotlin | Jetpack | Firebase | Android Studio | MVVM & Clean Code Architecture