具有共享偏好的 LiveData

LiveData with shared preferences

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

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

如何使用 LiveData 监听共享首选项的变化,然后使用新参数进行网络调用。

我看到您的挑战是在 API 在 ViewModel 或 LiveData 中调用时调用共享首选项值。

您可以在应用程序 class 中将您的共享首选项定义为全局(因此它将是全局的)

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);
   }
}

并且您可以通过在 ViewModel 中调用共享首选项来更新或保存值

/*Save to Shared Preferences*/
MyApplication.shared_preference.setLogin(true);

希望这对你有帮助,因为我在那里看到了你的问题,这对我有用并且能够在 API 调用中插入参数。

假设您的网络请求已经为您提供了 LiveData class。例如 Retrofit and a CallAdapter like LiveDataCallAdapter.

一旦您通过以下任一方法获得了最后一个观测值:

那么你可以将之前的LiveData应用于:

这是 UserViewModel.kt 中 Transformations.switchMap 的相关示例:

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)
        }
    }

下面一段很棒的代码是 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)
}

Java Code by 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);
}
}

SharedPreferenceBooleanLiveDataclass

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);
}

}

link中提到的下面的代码一样调用它:

 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();
 });

同样,如果使用 Preference Helper class,可以按如下方式调用 class: 只是一个例子:

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);
    }
}

并且在 activity class 中调用它如下: 创建对象:

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

观察如下:

sharedPreferenceLiveData.getBooleanLiveData(PreferenceKey.KEY_LOCATION_PERMISSION,false).observe(this,check->{
        if(check){
            setPermissionGranted(check);
        }
    });

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 

在您的偏好中添加以下代码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

//在其他 class 上获取你的 observer/flow/live 值,例如 MainActivity.class 等。

 CoroutineScope(Dispatchers.Main).launch{      
     appPreferences.getNotifyFlow().collect{
                   if (it){
                    Log.d("jai","true")
                   }else{
                     Log.d("jai","false")
                   }
                }
      }

Android 最近发布 DataStore 即:

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.

所以这是细分:

在项目的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"
}

数据库 class 看起来像:

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
        }
    }
}

在Activity中:

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

我创建了一个纯 kotlin 库来执行此操作 - https://github.com/Jintin/PreferencesExtension

我们需要做的就是:

val preferenceLiveData = preference.liveData<String>(MY_KEY)

preferenceLiveData.observe(this) {
    // get update here
}

并确保 preferenceLiveData 可以在 ViewModel 中并让 Activity/Fragment 观察它。 在此处查看示例: Activity, ViewModel

您可以在单个 LiveData 中组织所有 SharedPreferences 值

public class SharedPreferencesLiveData extends LiveData<ObservableArrayMap<String, Object>> {

    private final SharedPreferences mSharedPreference;

    public SharedPreferencesLiveData(final SharedPreferences sharedPreferences) {
        super(new ObservableArrayMap<String, Object>() {
            @Nullable
            @Override
            public Object put(String key, Object value) {
                final Object lastValue = super.get(key);
                if (!Objects.equals(value, lastValue)) {
                    if (value instanceof Boolean) {
                        sharedPreferences.edit().putBoolean(key, (Boolean) value).apply();
                    } else if (value instanceof Float) {
                        sharedPreferences.edit().putFloat(key, (Float) value).apply();
                    } else if (value instanceof String) {
                        sharedPreferences.edit().putString(key, (String) value).apply();
                    } else if (value instanceof Integer) {
                        sharedPreferences.edit().putInt(key, (Integer) value).apply();
                    } else if (value instanceof Long) {
                        sharedPreferences.edit().putLong(key, (Long) value).apply();
                    } else if (value instanceof Set) {
                        sharedPreferences.edit().putStringSet(key, (Set<String>) value).apply();
                    } else if (value == null) {
                        sharedPreferences.edit().remove(key).apply();
                    } else {
                        throw new IllegalArgumentException("value=" + value + " data type not support");
                    }
                    return super.put(key, value);
                } else
                    return lastValue;
            }
        });
        mSharedPreference = sharedPreferences;
    }

    @Override
    protected void onActive() {
        super.onActive();
        getValue().clear();
        getValue().putAll((SimpleArrayMap<? extends String, ?>) new ArrayMap<String, Object>() {{
            putAll(mSharedPreference.getAll());
        }});
        mSharedPreference.registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        mSharedPreference.unregisterOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);
    }

    SharedPreferences.OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, String key) {
            if (sharedPreferences.contains(key)) {
                getValue().put(key, sharedPreferences.getAll().get(key));
            } else {
                getValue().remove(key);
            }
        }
    };
}

然后在 ViewModel 中声明 SharedPreferences 的 LiveData

public static class ViewModel extends AndroidViewModel {
    public final SharedPreferencesLiveData sharedPreferenceLiveData = new SharedPreferencesLiveData(getApplication().getSharedPreferences("XXX", 0));

    public ViewModel(@NonNull Application application) {
        super(application);
    }
}

然后从 XML 布局

访问和更新(双向数据绑定)您的 SharedPreferences
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="viewModel"
            type="com.xxx.sharedpreferencedatabindingtest.MainActivity.ViewModel" />
    </data>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <CheckBox
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:checked='@={((Boolean)viewModel.sharedPreferenceLiveData["XXXX"])}'
            android:text="XXX" />

        <CheckBox
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:checked='@={((Boolean)viewModel.sharedPreferenceLiveData["XXXX"])}'
            android:text="XXX" />

        <SeekBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="1000"
            android:min="0"
            android:progress='@={(Integer)(viewModel.sharedPreferenceLiveData["YYYY"])}' />

        <SeekBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="1000"
            android:min="0"
            android:progress='@={(Integer)(viewModel.sharedPreferenceLiveData["YYYY"])}' />

    </LinearLayout>
</layout>