I have a settings screen where I am setting some values. When I set those values it gets saved in shared preferences and these values are needed in my request to the network
Add below dependency in build.gradle(:app)
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6" // replace with updated version
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6"// replace with updated version
Add Below code inyYour preference class/utils
private var mPrefs: SharedPreferences =
mContext.getSharedPreferences(AppConstant.PREF_NAME, Context.MODE_PRIVATE)
private val _constSate = MutableStateFlow(mPrefs.getBoolean(IS_NOTIFY,false))
// function for set data to preference and add to Stateflow.
fun setData(isNotify: Boolean){
// mPrefs = instance of your preference
mPrefs.edit().putBoolean(IS_NOTIFY, isNotify).apply()
_constSate.value = isNotify
}
//function for get observer/flow/live boolean value
fun getNotifyFlow() : StateFlow<Boolean> = _constSate
//get your observer/flow/live value on other class e.g MainActivity.class etc..
CoroutineScope(Dispatchers.Main).launch{
appPreferences.getNotifyFlow().collect{
if (it){
Log.d("jai","true")
}else{
Log.d("jai","false")
}
}
}
I've create a pure kotlin lib to do this - https://github.com/Jintin/PreferencesExtension
All we need to do is something like:
val preferenceLiveData = preference.liveData<String>(MY_KEY)
preferenceLiveData.observe(this) {
// get update here
}
And sure the preferenceLiveData can be inside ViewModel and let Activity/Fragment observe it. Check out the example here: Activity, ViewModel
Android recently released DataStore which is:
Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally.
If you're currently using SharedPreferences to store data, consider migrating to DataStore instead.
So here is the breakdown:
In the build.gradle
of the project:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
dependencies {
...
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha04"
}
The database class would look like:
class SettingsSharedPreference private constructor(context: Context) {
private val dataStore = context.createDataStore(name = "settings")
companion object {
val SCREEN_ORIENTATION = preferencesKey<String>("screen_orientation")
@Volatile
private var instance: SettingsSharedPreference? = null
private val lock = Any()
operator fun invoke(context: Context) = instance ?: synchronized(lock) {
instance ?: SettingsSharedPreference(context).also { instance = it }
}
}
val screenOrientationFlow: Flow<String> = dataStore.data
.map { preferences ->
preferences[SCREEN_ORIENTATION] ?: "landscape"
}
//TODO: You should use enum for screenOrientation, this is just an example
suspend fun setScreenOrientation(screenOrientation: String) {
dataStore.edit { preferences ->
preferences[SCREEN_ORIENTATION] = screenOrientation
}
}
}
In the Activity:
val settingsSharedPreference by lazy {
SettingsSharedPreference.invoke(this)
}
...
settingsSharedPreference.setScreenOrientation("portrait")
...
settingsSharedPreference.screenOrientationFlow.asLiveData().observe(this) { screenOrientation ->
...
}
i see your challenge is calling Shared Preferences Value when API Calling in ViewModel or LiveData.
You may define your shared preference as global in Application class ( so it will be global)
public class MyApplication extends Application {
public static AppPreferences shared_preference;
/*On Create Application Create AppPreferences*/
@Override
public void onCreate() {
super.onCreate();
shared_preference = AppPreferences.getInstance(this);
}
}
And you may update or save value by calling Shared Preference in your ViewModel
/*Save to Shared Preferences*/
MyApplication.shared_preference.setLogin(true);
Wish this help you, cause i see your problem there, This is works for me and able to insert param in API Call.
Assuming your network request is already providing you a LiveData class. For example with Retrofit and a CallAdapter like LiveDataCallAdapter.
Once you have the last observed value by either:
OnSharedPreferenceChangeListener
, as you already mentioned, to update a MutableLiveDataThen you can apply the previous LiveData to either:
This is the related example for the Transformations.switchMap in UserViewModel.kt:
private val _login = MutableLiveData<String>()
val login: LiveData<String>
get() = _login
val repositories: LiveData<Resource<List<Repo>>> = Transformations
.switchMap(_login) { login ->
if (login == null) {
AbsentLiveData.create()
} else {
repoRepository.loadRepos(login)
}
}
The following awesome piece of code is LiveData Implementation of SharedPreference. It works perfectly.
package com.chargingwatts.chargingalarm.util.preference;
import android.arch.lifecycle.LiveData
import android.content.SharedPreferences
abstract class SharedPreferenceLiveData<T>(val sharedPrefs: SharedPreferences,
val key: String,
val defValue: T) : LiveData<T>() {
private val preferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
if (key == this.key) {
value = getValueFromPreferences(key, defValue)
}
}
abstract fun getValueFromPreferences(key: String, defValue: T): T
override fun onActive() {
super.onActive()
value = getValueFromPreferences(key, defValue)
sharedPrefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
}
override fun onInactive() {
sharedPrefs.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
super.onInactive()
}
}
class SharedPreferenceIntLiveData(sharedPrefs: SharedPreferences, key: String, defValue: Int) :
SharedPreferenceLiveData<Int>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: Int): Int = sharedPrefs.getInt(key, defValue)
}
class SharedPreferenceStringLiveData(sharedPrefs: SharedPreferences, key: String, defValue: String) :
SharedPreferenceLiveData<String>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: String): String = sharedPrefs.getString(key, defValue)
}
class SharedPreferenceBooleanLiveData(sharedPrefs: SharedPreferences, key: String, defValue: Boolean) :
SharedPreferenceLiveData<Boolean>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: Boolean): Boolean = sharedPrefs.getBoolean(key, defValue)
}
class SharedPreferenceFloatLiveData(sharedPrefs: SharedPreferences, key: String, defValue: Float) :
SharedPreferenceLiveData<Float>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: Float): Float = sharedPrefs.getFloat(key, defValue)
}
class SharedPreferenceLongLiveData(sharedPrefs: SharedPreferences, key: String, defValue: Long) :
SharedPreferenceLiveData<Long>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: Long): Long = sharedPrefs.getLong(key, defValue)
}
class SharedPreferenceStringSetLiveData(sharedPrefs: SharedPreferences, key: String, defValue: Set<String>) :
SharedPreferenceLiveData<Set<String>>(sharedPrefs, key, defValue) {
override fun getValueFromPreferences(key: String, defValue: Set<String>): Set<String> = sharedPrefs.getStringSet(key, defValue)
}
fun SharedPreferences.intLiveData(key: String, defValue: Int): SharedPreferenceLiveData<Int> {
return SharedPreferenceIntLiveData(this, key, defValue)
}
fun SharedPreferences.stringLiveData(key: String, defValue: String): SharedPreferenceLiveData<String> {
return SharedPreferenceStringLiveData(this, key, defValue)
}
fun SharedPreferences.booleanLiveData(key: String, defValue: Boolean): SharedPreferenceLiveData<Boolean> {
return SharedPreferenceBooleanLiveData(this, key, defValue)
}
fun SharedPreferences.floatLiveData(key: String, defValue: Float): SharedPreferenceLiveData<Float> {
return SharedPreferenceFloatLiveData(this, key, defValue)
}
fun SharedPreferences.longLiveData(key: String, defValue: Long): SharedPreferenceLiveData<Long> {
return SharedPreferenceLongLiveData(this, key, defValue)
}
fun SharedPreferences.stringSetLiveData(key: String, defValue: Set<String>): SharedPreferenceLiveData<Set<String>> {
return SharedPreferenceStringSetLiveData(this, key, defValue)
}