具有共享首选项的LiveData

nic*_*tdr 10 android android-sharedpreferences android-livedata

我有一个设置屏幕,在其中设置一些值。设置这些值时,它将保存在共享首选项中,并且在我对网络api调用的请求中需要这些值作为参数。

现在,我可以在活动中使用侦听器共享首选项,然后进行api调用并获取新数据,但是我想将其与LiveData一起使用。

如何使用LiveData侦听共享首选项中的更改,然后使用新参数进行网络呼叫。

Abh*_*hra 14

以下很棒的代码是SharedPreference的LiveData实现。它运作完美。

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这是这个漂亮片段的Java代码版本:https://gist.github.com/idish/f46a8327da7f293f943a5bda31078c95 (2认同)
  • 对于想知道为什么“sharedPrefs.getString(key, defValue)”可能为空的人,[这篇文章](/sf/answers/4012632641/)很好地解释了这一点。 (2认同)
  • 这可以通过抽象类重写 `getValue()` 并返回不可为空的 `super.getValue() ?: getValueFromPreferences(key, defValue)` 来改进,因此也可以直接检索不可为空的 `value` 而无需观察。 (2认同)

Sim*_*mer 5

Java的代码Idish,虽然他在这里评论,但不知道,他为什么不将其添加为答案。

在下面粘贴相同的代码:

public abstract class SharedPreferenceLiveData<T> extends LiveData<T> {

SharedPreferences sharedPrefs;
String key;
public T defValue;

public SharedPreferenceLiveData(SharedPreferences prefs, String key, T defValue) {
    this.sharedPrefs = prefs;
    this.key = key;
    this.defValue = defValue;
}

private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (SharedPreferenceLiveData.this.key.equals(key)) {
            setValue(getValueFromPreferences(key, defValue));
        }
    }
};
abstract T getValueFromPreferences(String key, T defValue);

@Override
protected void onActive() {
    super.onActive();
    setValue(getValueFromPreferences(key, defValue));
    sharedPrefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}

@Override
protected void onInactive() {
    sharedPrefs.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
    super.onInactive();
}
public SharedPreferenceLiveData<Boolean> getBooleanLiveData(String key, Boolean defaultValue) {
    return new SharedPreferenceBooleanLiveData(sharedPrefs,key, defaultValue);
}
}
Run Code Online (Sandbox Code Playgroud)

SharedPreferenceBooleanLiveData类

public class SharedPreferenceBooleanLiveData extends SharedPreferenceLiveData<Boolean>{

public SharedPreferenceBooleanLiveData(SharedPreferences prefs, String key, Boolean defValue) {
    super(prefs, key, defValue);
}

@Override
Boolean getValueFromPreferences(String key, Boolean defValue) {
    return sharedPrefs.getBoolean(key, defValue);
}

}
Run Code Online (Sandbox Code Playgroud)

像在此链接中提到的以下代码那样调用:

 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
 SharedPreferenceStringLiveData sharedPreferenceStringLiveData = new SharedPreferenceStringLiveData(preferences, "cid", "");
 sharedPreferenceStringLiveData.getStringLiveData("cid", "").observe(this, cid -> {
            Toast.makeText(this, "Change in CID "+cid, Toast.LENGTH_SHORT).show();
 });
Run Code Online (Sandbox Code Playgroud)

同样,如果使用Preference Helper类,则可以按以下方式调用该类:只是一个示例:

public class PreferenceManager {
private SharedPreferenceBooleanLiveData sharedPreferenceLiveData;

public SharedPreferenceBooleanLiveData getSharedPrefs(){
        return sharedPreferenceLiveData;
    }

public void setSharedPreferences(String key, boolean value) {

        SharedPreferences userDetails = context.getSharedPreferences(APP_PREFERENCE,
            Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = userDetails.edit();
        editor.putBoolean(key, value);
        editor.apply();
        sharedPreferenceLiveData = new SharedPreferenceBooleanLiveData(userDetails,key,value);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在活动类中按如下所示调用它:创建一个对象:

SharedPreferenceBooleanLiveData sharedPreferenceLiveData;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    sharedPreferenceLiveData = preferenceManager.getSharedPrefs();
}
Run Code Online (Sandbox Code Playgroud)

并观察如下:

sharedPreferenceLiveData.getBooleanLiveData(PreferenceKey.KEY_LOCATION_PERMISSION,false).observe(this,check->{
        if(check){
            setPermissionGranted(check);
        }
    });
Run Code Online (Sandbox Code Playgroud)


jai*_*ior 5

Android 最近发布了DataStore,它是:

Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致和事务方式存储数据。

如果您当前使用 SharedPreferences 来存储数据,请考虑迁移到 DataStore。

所以这是细分:

build.gradle项目中:

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"
}
Run Code Online (Sandbox Code Playgroud)

数据库类如下所示:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在活动中:

val settingsSharedPreference by lazy {
    SettingsSharedPreference.invoke(this)
}
...
settingsSharedPreference.setScreenOrientation("portrait")    
...
settingsSharedPreference.screenOrientationFlow.asLiveData().observe(this) { screenOrientation ->
    ...
}
Run Code Online (Sandbox Code Playgroud)