Является ли новое хранилище данных Jetpack только для Kotlin?

#java #android #kotlin #android-jetpack #android-jetpack-datastore

#java #Android #kotlin #android-jetpack #android-jetpack-хранилище данных

Вопрос:

Я читал о новой библиотеке из Jetpack (теперь в альфа-версии) — хранилище данных Jetpack.

Из документации ясно, что это своего рода Shared Preferences' killer

Хранилище данных Jetpack — это решение для хранения данных, которое позволяет хранить пары ключ-значение или типизированные объекты с буферами протокола

Хранилище данных использует сопрограммы Kotlin и Flow для хранения данных асинхронно, последовательно и транзакционно

Если в настоящее время вы используете SharedPreferences для хранения данных, рассмотрите возможность перехода на хранилище данных

Если я ничего не упущу, вы не сможете использовать эту библиотеку в Java. Я прав? Лично я использую Kotlin, но для меня это своеобразный прецедент для библиотеки AndroidX.

Ответ №1:

Вы можете использовать хранилище данных только в RxJava. В обычной java теперь вы можете использовать только SharedPreferences. Давайте сравним настройки хранилища данных RxJava с SharedPreferences

1) доступ

Хранилище данных:

 RxDataStore<Preferences> dataStore =
  new RxPreferenceDataStoreBuilder(context, /*name=*/ "settings").build();
  

SharedPreferences:

 SharedPreferences sharedPref = context.getSharedPreferences(
        getString(R.string.preference_file_key), Context.MODE_PRIVATE);
  

2) прочитайте:

Хранилище данных: определите ключ для вашего значения (в примере для значения int), а затем получите доступ к данным хранилища данных: PreferencesKeys.int («example_counter»)

datastore.data().map()

data() — доступ к данным хранилища данных. Это свойство возвращает поток

map() — возвращает поток, содержащий результаты применения данной функции к каждому значению исходного потока

SharedPreferences

SharedPref.getInt(«highScoreKey», 0);

Чтобы получить значения из общего файла настроек, укажите ключ для нужного значения со значением по умолчанию (o здесь в примере)

3) напишите

Хранилище данных:

dataStore.updateDataAsync()

транзакционное обновление данных в хранилище данных

SharedPreferences:

Использование SharedPreferences.Редактор передайте ключи и значения, которые вы хотите записать, с помощью таких методов, как putInt() и putString(). Затем вызовите apply() или commit(), чтобы сохранить изменения. Пример

Вывод: developer.android.com предлагает рассмотреть возможность перехода к хранилищу данных вместо SharedPreferences. Но, хотя Java не поддерживает хранилище данных, лучше использовать SharedPreferences. если ваше приложение использует Kotlin или RxJava — лучше использовать хранилище данных

Ответ №2:

13 января 2021 г.

Выпущена версия 1.0.0-alpha06. Добавлена поддержка RxJava 2/3, поэтому хранилище данных теперь можно использовать на Java.

Добавлены оболочки RxJava для хранилища данных. Артефакты хранилища данных-rxjava2 / 3 содержат оболочки для основных API-интерфейсов хранилища данных (RxDataStore, RxDataStoreBuilder и RxDataMigration). Артефакты datastore-preferences-rxjava2 / 3 содержат конструктор для создания хранилища данных настроек.

Для этого вы должны добавить зависимости:

 // optional - RxJava2 support
implementation "androidx.datastore:datastore-rxjava2:1.0.0-alpha06"

// optional - RxJava3 support
implementation "androidx.datastore:datastore-rxjava3:1.0.0-alpha06"
  

Кроме того, теперь официальная документация хранилища данных содержит эквиваленты примеров кода для Java.

Комментарии:

1. Могу ли я использовать хранилище данных в обычной Java? Или только в RxJava-приложениях

2. @Виктор Поздняков, на данный момент из коробки у вас есть только два варианта — сопрограммы Kotlin и RxJava. Хотя библиотека все еще находится в альфа-версии, возможно, будут какие-то изменения (кто знает, может ListenableFuture быть, скоро будет добавлена поддержка Guava)

3. ДА. В простых java-проектах нам остается использовать SharedPreferences. Надеюсь, в будущем хранилище данных можно будет использовать на обычной Java

Ответ №3:

Я уверен, что они не планируют делать это для Java.

Хранилище данных, построенное на сопрограммах Kotlin и Flow, предоставляет две разные реализации: хранилище данных Proto, которое позволяет хранить типизированные объекты (поддерживаемые буферами протокола) и хранилище данных Preferences, в котором хранятся пары ключ-значение. Данные хранятся асинхронно, последовательно и транзакционно, преодолевая большинство недостатков SharedPreferences.

Насколько я понимаю, сопрограммы / потоки Kotlin недоступны для java. Вы можете прочитать больше здесь, хорошая статья от Florina.

Ответ №4:

Я согласен с ответом @Victor Pozdnyakov. Итак, я не буду здесь повторять это, но я действительно изо всех сил пытался заставить это работать на java только для сохранения одного значения; Я не нашел никаких указаний на это, поэтому мне пришлось копаться в RxJava документации.

Вот пример сохранения значения int и возврата его без непрерывного наблюдения за данными (точно так же, как вы делаете с SharedPreferences )

Зависимости:

 implementation "androidx.datastore:datastore-preferences:1.0.0"

// RxJava3 support
implementation "androidx.datastore:datastore-preferences-rxjava3:1.0.0"

implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
  

Приведенный пример с описанием комментариев:

 public class MainActivity extends AppCompatActivity {

    // Data store object
    RxDataStore<Preferences> dataStore =
            new RxPreferenceDataStoreBuilder(this, "settings").build();

    // Key for saving integer value
    Preferences.Key<Integer> SOME_KEY = PreferencesKeys.intKey("SOME_KEY");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Storing an int value to DataStore with the key of SOME_KEY
        saveInt(SOME_KEY, 1050);

        // Read the data immediately as it's already observed
        observeInt(SOME_KEY, value -> runOnUiThread(() ->
                Toast.makeText(this, "Observed Value: "   value, Toast.LENGTH_SHORT).show()));


        // Wait some time before reading the data as it takes time until it's stored; 
        // so don't call it here, but on some other event
        readInt(SOME_KEY, value -> runOnUiThread(() ->
                Toast.makeText(this, "Value: "   value, Toast.LENGTH_SHORT).show()));

    }

    /**
     * Saving an int value to DataStore with some key
     *
     * @param key:   The key associated to the value need to be stored
     * @param value: The value to be stored
     */
    private void saveInt(Preferences.Key<Integer> key, int value) {
        dataStore.updateDataAsync(prefsIn -> {
            MutablePreferences mutablePreferences = prefsIn.toMutablePreferences();
            mutablePreferences.set(key, value);
            return Single.just(mutablePreferences);
        }).subscribe();

    }

    /**
     * Returning an int value from the DataStore which is associated to some key,
     * once the result is returned, the subscription is disposed.
     *
     * @param key:      The key associated to the value need to be stored
     * @param listener: The value is returned in a worker thread, and returned to the
     *                  caller using a listener pattern
     */
    public void readInt(Preferences.Key<Integer> key, IntListener listener) {
        Flowable<Integer> flowable =
                dataStore.data().map(prefs -> prefs.get(key));

        flowable.firstOrError().subscribeWith(new DisposableSingleObserver<Integer>() {

            @Override
            public void onSuccess(@NotNull Integer value) {
                listener.intValue(value);
            }

            @Override
            public void onError(@NotNull Throwable error) {
                error.printStackTrace();
            }
        }).dispose();
    }


    /**
     * Subscribing an observer to an int value in the DataStore which is associated to some key,
     * The subscription submits any change to the value
     *
     * @param key:      The key associated to the value need to be stored
     * @param listener: The value is returned in a worker thread, and returned to the
     *                  caller using a listener pattern
     */
    public void observeInt(Preferences.Key<Integer> key, IntListener listener) {
        Flowable<Integer> flowable =
                dataStore.data().map(prefs -> prefs.get(key));

        flowable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()) // AndroidSchedulers requires ` implementation "io.reactivex.rxjava3:rxandroid:3.0.0" `
                .subscribe(new FlowableSubscriber<Integer>() {

                    @Override
                    public void onSubscribe(@NonNull Subscription s) {
                        s.request(Long.MAX_VALUE);
                    }

                    @Override
                    public void onNext(Integer value) {
                        listener.intValue(value);
                    }

                    @Override
                    public void onError(Throwable t) {
                        t.printStackTrace();
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }


    interface IntListener {
        void intValue(int value);
    }

}