Введение
В моем приложении для Android я использовал SharedPreferences для хранения простых строк для функциональности. Недавно я узнал, что настройки по умолчанию устарели. Так что я пошел и искал альтернативы.
Довольно быстрый поиск в Google показал в качестве альтернативы JetPack DataStore-Library. Я знал, что существует возможность реализации базы данных SQLite, но мне хотелось иметь другой облегченный вариант, такой как SharedPreferences: небольшой объем кода, но высокая применимость.
Мне удалось найти множество руководств по Kotlin, но я программировал на Java и хотел продолжать это делать. С инструкциями на сайте я мог начать думать о том, как это может работать. Но процедура оказалась не такой простой, как я думал.
Тем не менее, поскольку я не нашел хорошего руководства о том, как это сделать, но нашел решение, позволяющее заставить его работать очень похоже на SharedPreferences, я хочу поделиться процедурой.
инструкции
Я работаю с Android Studio IDE в версии Flamingo | 2022.2.1. Также хочу отметить, что Java-версия 11 и я использую лямбда-выражения.
Чтобы использовать DataStore-Library, я добавил следующие зависимости в файл app-gradle:
//DataStore instead of SharedPreferences implementation "androidx.datastore:datastore-preferences:1.0.0" //RxJava2 support implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"
После быстрой синхронизации библиотеки должны быть доступны для использования.
В верхней части упражнения я инициализировал переменную dataStoreRX типа RxDataStore для запуска, а затем в методе onCreate DataStore можно построить с помощью DataStoreBuilder. :
RxDataStore<Preferences> dataStoreRX; protected void onCreate(Bundle savedInstanceState) { ... dataStoreRX = new RxPreferenceDataStoreBuilder(this, "name_for_datastore").build(); }
На этом я надеялся практически закончить, DataStore построен, так что я могу начать сохранять и извлекать значения. Я думал, что это будет конец, в любом случае, если вы захотите использовать DataStore только в одном действии, это будет конец.
Однако, если вы хотите, чтобы DataStore сохранялся через несколько действий, вы должны принять во внимание, что может присутствовать только один экземпляр:
Никогда не создавайте более одного экземпляра
DataStore
для данного файла в одном процессе.
Но я не хотел помещать DataStore в Bundle и всегда отправлять его следующей активности с помощью putExtra. Поскольку я хотел иметь возможность переключаться между действиями, не переписывая код для всего этого, я искал другую возможность.
Я нашел Синглтон, с помощью которого можно сохранить что угодно как отдельный экземпляр и использовать его не только в одном действии. Это в значительной степени предпосылка DataStore.
Итак, я создал новый java-класс DataStoreSingleton, конкретное имя выбрать не важно, просто оно должно быть таким же в самом классе:
public class DataStoreSingleton { RxDataStore<Preferences> datastore; private static final DataStoreSingleton ourInstance = new DataStoreSingleton(); public static DataStoreSingleton getInstance() { return ourInstance; } private DataStoreSingleton() { } public void setDataStore(RxDataStore<Preferences> datastore) { this.datastore = datastore; } public RxDataStore<Preferences> getDataStore() { return datastore; } }
С помощью двух функций setDataStore и getDataStore можно использовать Singleton. В методе onCreate я реализовал это так:
DataStoreSingleton dataStoreSingleton = DataStoreSingleton.getInstance(); if (dataStoreSingleton.getDataStore() == null) { dataStoreRX = new RxPreferenceDataStoreBuilder(this, TAG_STORE_NAME).build(); } else { dataStoreRX = dataStoreSingleton.getDataStore(); } dataStoreSingleton.setDataStore(dataStoreRX);
Если DataStore еще не построен (getDataStore возвращает null), он создается с помощью упомянутого DataStoreBuilder, в противном случае он назначается переменной. В любом случае для этого и следующего действия устанавливается Singleton for DataStore.
Чтобы сохранить значение, я создал метод putStringValue, чтобы он выглядел и работал как функция SharedPreferences:
public boolean putStringValue(String Key, String value){ boolean returnvalue; Preferences.Key<String> PREF_KEY = PreferencesKeys.stringKey(Key); Single<Preferences> updateResult = dataStoreRX.updateDataAsync(prefsIn -> { MutablePreferences mutablePreferences = prefsIn.toMutablePreferences(); mutablePreferences.set(PREF_KEY, value); return Single.just(mutablePreferences); }).onErrorReturnItem(pref_error); returnvalue = updateResult.blockingGet() != pref_error; return returnvalue; }
То же самое с получением значения с помощью функции getStringValue:
String getStringValue(String Key) { Preferences.Key<String> PREF_KEY = PreferencesKeys.stringKey(Key); Single<String> value = dataStoreRX.data().firstOrError().map(prefs -> prefs.get(PREF_KEY)).onErrorReturnItem("null"); return value.blockingGet(); }
Довольно небольшой объем кода, но мне потребовалось относительно много времени, чтобы понять, что blockingGet можно использовать для извлечения значения из Single.
DataStore не принимает обычные строки в качестве ключей, поэтому мы должны создать Preference.Keys типа String. Соответствующее значение также должно быть строкой (ну, конечно, нет? :)). Но это также означает, что для хранения другого типа мы должны добавить разные методы (putBooleanValue с целым числом в качестве ключа, например). . Чтобы поймать ошибку при сохранении или извлечении значений, я добавил onErrorReturnItem, который делает именно то, на что он похож: он возвращает указанный элемент, если возникает ошибка. Для сохранения это должна быть переменная Preferences, но поскольку мы извлекаем строку, это может быть переменная String. Pref_error не обязательно должен быть таким особенным, он используется только для проверки того, ЕСЛИ он возвращается, то возвращается соответствующее значение. Строка — это буквально просто «ошибка», которая возвращается.
Эти два метода сохраняют и извлекают значения почти так же, как и с SharedPreferences.
Опираясь на это
Чтобы было еще проще, я снова создал новый java-класс: DataStoreHelper
public class DataStoreHelper { Activity activity; RxDataStore<Preferences> dataStoreRX; Preferences pref_error = new Preferences() {...}; public DataStoreHelper(Activity activity, RxDataStore<Preferences> dataStoreRX) { this.activity = activity; this.dataStoreRX = dataStoreRX; } public boolean putStringValue(String Key, String value){...} String getStringValue(String Key) {...} public boolean putBoolValue(String Key, boolean value){...} boolean getBoolValue(String Key) {...} }
В этом классе я могу один раз перечислить все необходимые переменные и методы и вызвать их из любого действия с помощью:
DataStoreHelper dataStoreHelper; dataStoreHelper = new DataStoreHelper(this, dataStoreRX); dataStoreHelper.putStringValue(TAG_SEND, TAG_ONLINE); dataStoreHelper.getStringValue(TAG_SEND);
Я надеюсь, что этот урок поможет вам, если вы окажетесь в ситуации, в которой оказался я! Удачного кодирования, и не стесняйтесь спрашивать о чем угодно.