android 具有共享首选项的LiveData

kognpnkq  于 2023-02-02  发布在  Android
关注(0)|答案(9)|浏览(220)

我有一个设置屏幕,我在那里设置一些值。当我设置这些值时,它会保存在共享首选项中,这些值在我请求网络API调用时作为参数是需要的。
现在我可以在我的Activity中使用共享首选项的侦听器,然后进行API调用并获取最新数据,但我想将此功能与LiveData一起使用。
如何使用LiveData侦听共享首选项中的更改,然后使用新参数进行网络呼叫。

dgjrabp2

dgjrabp21#

下面这段代码是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)
}
ztigrdn8

ztigrdn82#

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

共享首选项布尔实时数据类

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

}

调用此链接中提到的以下代码:

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类,则可以按如下方式调用该类:仅举一例:

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

并在活动类中调用如下:创建对象:

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

v64noz0r3#

假设您的网络请求已经为您提供了一个LiveData类,例如Retrofit和一个CallAdapter(如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)
        }
    }
w6lpcovy

w6lpcovy4#

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

数据库类如下所示:

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

在活动中:

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

xjreopfe5#

我创建了一个纯kotlin库来完成此操作-https://github.com/Jintin/PreferencesExtension
我们要做的就是:

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

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

并确保preferenceLiveData可以在ViewModel内部,让Activity/Fragment观察它。ActivityViewModel

nwnhqdif

nwnhqdif6#

我看到您的挑战是在ViewModel或LiveData中调用API时调用共享首选项值。
您可以在Application类中将共享首选项定义为全局(因此它将是全局的)

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调用。

xfyts7mz

xfyts7mz7#

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

//获取其他类上的观察者/流/实时值,例如MainActivity.class等。

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

uajslkp68#

您可以在单个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>
uxhixvfz

uxhixvfz9#

我还想知道如何监听Preferences Activity中的首选项更改,它是PreferenceFragmentCompat的片段,但事实证明,如果MainActivity在按下“Up”按钮后刷新,则无需“订阅”更改。在AndroidManifest中,如果设置了android:launchMode,它应该是“standard”(这将导致MainActivity在从另一个Activity导航到它之后被刷新)。然后,您可以简单地使用PreferenceManager.getDefaultSharedPreferences来获得首选项,如文档中所述,可以从任何地方访问PreferenceManager.getDefaultSharedPreferences

相关问题