0

Como utilizar DataStore no lugar de SharedPreferences

#Kotlin #Android #Arquitetura de Sistemas
Matheus Miranda
Matheus Miranda

Assim como SharedPreferences, o DataStore permite armazenar dados em chave-valor ou objetos tipados e é a maneira recomendada pela Google agora. A diferença é que o DataStore utiliza de Coroutines e Flow para fazer tudo de forma assíncrona.


Neste artigo vamos tratar do Preferences DataStore, que é uma implementação mais simples em relação a Proto DataStore.


Primeiro, precisamos da dependência no build.gradle (módulo do app)

// DataStore
implementation 'androidx.datastore:datastore-preferences:1.0.0'

Obs: Dependendo da sua implementação, não esqueça das dependências de lifecycle/extensions, ViewModel, etc.


Vamos utilizar o DataStore para descobrir se o usuário já logou antes ou fez logout de nosso app a partir de um valor booleano.

Crie uma classe separada apenas para lidar com os métodos de leitura e escrita em nosso DataStore, podemos chamá-la de DataStorePref, ela precisa receber um Context.

class DataStorePref(private val context: Context)


Defina um companion object para criarmos o DataStore. Ele terá o nome de "settings", e já podemos definir uma chave "login". O dataStore será acessado a partir do Context.

companion object {
    private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
    const val KEY = "login"
}


Agora precisamos de 2 métodos de acesso. Ambos precisam ser suspend functions e precisamos receber a chave para saber onde ler e escrever.

/**
 * Salva o valor passado pelo usuário em hasLoggedIn.
 */
suspend fun saveToDataStore(key: String, hasLoggedIn: Boolean) {
    val dataStoreKey = booleanPreferencesKey(key)
    context.dataStore.edit { settings ->
        settings[dataStoreKey] = hasLoggedIn
    }
}

/**
 * Leitura do DataStore. O first() retorna o primeiro elemento
 * emitido pelo Flow.
 */
suspend fun readFromDataStore(key: String): Boolean? {
    val dataStoreKey = booleanPreferencesKey(key)
    val preferences = context.dataStore.data.first()
    return preferences[dataStoreKey]
}


E a classe completa:

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 kotlinx.coroutines.flow.first

class DataStorePref(private val context: Context) {

    suspend fun saveToDataStore(key: String, hasLoggedIn: Boolean) {
        val dataStoreKey = booleanPreferencesKey(key)
        context.dataStore.edit { settings ->
            settings[dataStoreKey] = hasLoggedIn
        }
    }

    suspend fun readFromDataStore(key: String): Boolean? {
        val dataStoreKey = booleanPreferencesKey(key)
        val preferences = context.dataStore.data.first()
        return preferences[dataStoreKey]
    }

    companion object {
        private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
        const val KEY = "login"
    }
}


Agora, no nosso Fragment de Login por exemplo, podemos chamar o DataStore para descobrir se o usuário já logou, e salvar caso seja o primeiro acesso.


Vamos fazer uma inicialização tardia da classe:

private lateinit var dataStorePref: DataStorePref


Vamos ler do dataStorePref e definir uma ação caso o usuário já tenha logado antes. Uma suspend function precisa ser chamada dentro de um escopo de coroutine, por isso estamos utilizando o lifecycleScope.launch

dataStorePref = DataStorePref(requireContext())
viewLifecycleOwner.lifecycleScope.launch {
    val hasLoggedIn = dataStorePref.readFromDataStore(DataStorePref.
KEY)
    if (hasLoggedIn == true) {
       // Aqui voce define o que acontece quando o usuário ja logou
    }
}


Caso seja o primeiro acesso, após realizar a validação dos dados de login, podemos chamar uma função que salva "true" no dataStorePref.

private fun savaToDataStore() {
    viewLifecycleOwner.lifecycleScope.launch {
        dataStorePref.saveToDataStore(DataStorePref.KEY, true)
    }
}


Caso o usuário faça o logout em alguma outra tela, basta chamar o método save novamente, desta vez passando "false"

val dataStorePref = DataStorePref(requireContext())

viewLifecycleOwner.lifecycleScope.launch {
    dataStorePref.saveToDataStore(DataStorePref.KEY, false)
}


Recomendo a todos que façam a leitura da documentação. No entanto, às vezes pode ser um pouco confuso, e um exemplo prático com código facilita o entendimento. Qualquer dúvida estou à disposição.


Bons estudos!

0
3

Comentários (0)

Desenvolvedor Android Jr - https://github.com/matheus-miranda

Brasil