4

I've read about new library from Jetpack (now in alpha) - Jetpack Datastore.

It's clear from documentation that it's a sort of Shared Preferences' killer

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

If I don't miss anything you couldn't use this library in Java. Am I right? Personally I use Kotlin, but as for me it's a peculiar precedent for AndroidX library.

4

4 回答 4

2

January 13, 2021

Version 1.0.0-alpha06 was released. Support for RxJava 2/3 was added, so Datastore can be used in Java now.

Added RxJava wrappers for DataStore. The datastore-rxjava2/3 artifacts contain the wrappers for the core DataStore APIs (RxDataStore, RxDataStoreBuilder, and RxDataMigration). The datastore-preferences-rxjava2/3 artifacts contain a builder to construct a Preferences DataStore.

For that you should add dependencies:

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

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

In addition now Datastore's official documentation holds code's examples' equivalents for Java.

于 2021-01-16T07:45:21.847 回答
1

I pretty sure they do not hava plan to do it for java.

Built on Kotlin coroutines and Flow, DataStore provides two different implementations: Proto DataStore, that lets you store typed objects (backed by protocol buffers) and Preferences DataStore, that stores key-value pairs. Data is stored asynchronously, consistently, and transactionally, overcoming most of the drawbacks of SharedPreferences.

Kotlin coroutines/flow are not available to java as far as I am concern. You can read more here, a nice article from Florina.

于 2020-09-23T23:23:47.190 回答
1

You can use DataStore only in RxJava. In plain java you can use only SharedPreferences now. Let's compare RxJava DataStore Preferences with SharedPreferences

1) access

DataStore:

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

SharedPreferences:

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

2) read:

DataStore: define a key for your value (in example for int value) and then access data of datastore : PreferencesKeys.int("example_counter")

datastore.data().map()

data() - access the data of DataStore. This property returns a Flow

map() - returns a Flow which contains the results of applying the given function to each value of the original Flow

SharedPreferences

sharedPref.getInt("highScoreKey", 0);

To retrieve values from a shared preferences file provide the key for the value you want with default value (o here in example)

3) write

DataStore:

dataStore.updateDataAsync()

transactionally update data in a DataStore

SharedPreferences:

Using SharedPreferences.Editor pass the keys and values you want to write with methods such as putInt() and putString(). Then call apply() or commit() to save the changes. Example

Conclusion: developer.android.com suggests consider migrating to DataStore instead of SharedPreferences. But while Java doesn't support DataStore, it's better to use SharedPreferences. if your application uses Kotlin or RxJava - it's better to use DataStore

于 2021-03-18T09:50:10.053 回答
0

I am agreeing with @Victor Pozdnyakov answer. So, I won't reiterate here that, but I really struggled to get that working in java just for saving a single value; I didn't find any tuts on that, so I had to dig into RxJava documentation.

Here an example to store an int value and return it without continuous data observation (just like you do with SharedPreferences)

Dependencies:

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"

The example provided with describing comments:

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

}
于 2021-10-18T22:09:04.713 回答