新的Jetpack Datastore仅适用于Kotlin吗?

huangapple go评论70阅读模式
英文:

Is new Jetpack Datastore only for Kotlin?

问题

我已阅读关于Jetpack的新库(现在处于alpha版本) - Jetpack Datastore

从文档中可以清楚地看出,这是一种类似于Shared Preferences的替代方案

Jetpack DataStore是一种数据存储解决方案,允许您存储键值对或带有协议缓冲区的类型化对象。

DataStore使用Kotlin协程和Flow以异步、一致和事务方式存储数据。

如果您目前正在使用SharedPreferences存储数据,请考虑迁移到DataStore。

如果我没有漏掉什么,您不能在Java中使用这个库。我是对的吗?就我个人而言,我使用Kotlin,但对我来说,这是一个AndroidX库的特殊先例。

英文:

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.

答案1

得分: 4

以下是您要翻译的内容:

可以仅在 RxJava 中使用 DataStore。在纯 Java 中,您现在只能使用 SharedPreferences。让我们比较 RxJava 中的 DataStore 首选项和 SharedPreferences

1) 访问

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) 读取:

DataStore:
为您的值(例如整数值)定义一个键,然后访问数据存储的数据:PreferencesKeys.int("example_counter")

datastore.data().map()

data() - 访问 DataStore 的数据。此属性返回一个 Flow

map() - 返回一个包含将给定函数应用于原始 Flow 的每个值的结果的 Flow

SharedPreferences

sharedPref.getInt("highScoreKey", 0);

要从共享首选项文件检索值,请提供您想要的值的键和默认值(例如此处为示例中的 "o")

3) 写入

DataStore:

dataStore.updateDataAsync()

以事务方式更新 DataStore 中的数据

SharedPreferences:

使用 SharedPreferences.Editor 传递要写入的键和值,使用诸如 putInt() 和 putString() 等方法。然后调用 apply() 或 commit() 以保存更改。示例

结论: developer.android.com 建议考虑迁移到 DataStore,而不是 SharedPreferences。但在 Java 不支持 DataStore 的情况下,最好使用 SharedPreferences。如果您的应用程序使用 Kotlin 或 RxJava - 最好使用 DataStore。

英文:

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&lt;Preferences&gt; dataStore =
  new RxPreferenceDataStoreBuilder(context, /*name=*/ &quot;settings&quot;).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

答案2

得分: 3

2021年1月13日

发布了版本1.0.0-alpha06。添加了对RxJava 2/3的支持,因此现在可以在Java中使用Datastore。

> 添加了DataStore的RxJava封装。datastore-rxjava2/3构件包含了核心DataStore API的封装(RxDataStore、RxDataStoreBuilder和RxDataMigration)。datastore-preferences-rxjava2/3构件包含了构建Preferences DataStore的构建器。

要实现这一点,您需要添加依赖项:

// 可选 - RxJava2支持
implementation "androidx.datastore:datastore-rxjava2:1.0.0-alpha06"

// 可选 - RxJava3支持
implementation "androidx.datastore:datastore-rxjava3:1.0.0-alpha06"

此外,现在Datastore的官方文档中包含了Java代码示例的等效内容。

英文:

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 &quot;androidx.datastore:datastore-rxjava2:1.0.0-alpha06&quot;

// optional - RxJava3 support
implementation &quot;androidx.datastore:datastore-rxjava3:1.0.0-alpha06&quot;

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

答案3

得分: 1

我很确定他们没有计划为Java执行此操作。

基于Kotlin协程和Flow,DataStore提供了两种不同的实现方式:Proto DataStore,可以存储类型化对象(由协议缓冲支持),和Preferences DataStore,用于存储键值对。数据以异步、一致和事务性的方式存储,克服了大多数SharedPreferences的缺点。

据我所知,Kotlin协程/Flow在Java中不可用。
您可以在此处阅读更多信息,这是来自Florina的一篇很好的文章。

英文:

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.

答案4

得分: 1

以下是翻译好的内容:

我同意 @Victor Pozdnyakov 的答案。因此,我不会在这里重复那个,但是我在尝试在 Java 中使其工作时确实遇到了困难,只是为了保存一个单一的值;我没有找到任何关于这方面的教程,所以我不得不深入研究 RxJava 文档。

这里有一个示例,用于存储一个 int 值并在没有连续数据观察的情况下返回它(就像使用 SharedPreferences 一样)。

依赖项:

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

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

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

带有说明性注释的示例:

public class MainActivity extends AppCompatActivity {

    // 数据存储对象
    RxDataStore<Preferences> dataStore =
            new RxPreferenceDataStoreBuilder(this, "settings").build();

    // 用于保存整数值的键
    Preferences.Key<Integer> SOME_KEY = PreferencesKeys.intKey("SOME_KEY");

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

        // 将整数值存储到 DataStore,使用 SOME_KEY 键
        saveInt(SOME_KEY, 1050);

        // 立即读取数据,因为它已经被观察
        observeInt(SOME_KEY, value -> runOnUiThread(() ->
                Toast.makeText(this, "观察到的值:" + value, Toast.LENGTH_SHORT).show()));

        // 在读取数据之前等待一些时间,因为需要一些时间才能存储;
        // 因此不要在这里调用它,而是在其他某个事件上调用
        readInt(SOME_KEY, value -> runOnUiThread(() ->
                Toast.makeText(this, "值:" + value, Toast.LENGTH_SHORT).show()));
    }

    /**
     * 将整数值保存到 DataStore,使用某个键
     *
     * @param key:   与要存储的值关联的键
     * @param value: 要存储的值
     */
    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();
    }

    /**
     * 从 DataStore 返回与某个键关联的整数值,
     * 一旦返回结果,订阅就会被处理掉。
     *
     * @param key:      与要存储的值关联的键
     * @param listener: 该值在工作线程中返回,并使用监听器模式返回给调用者
     */
    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();
    }

    /**
     * 订阅一个观察者到与某个键关联的整数值,
     * 订阅会将任何对该值的更改提交
     *
     * @param key:      与要存储的值关联的键
     * @param listener: 该值在工作线程中返回,并使用监听器模式返回给调用者
     */
    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 需要 `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);
    }
}
英文:

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 &quot;androidx.datastore:datastore-preferences:1.0.0&quot;
// RxJava3 support
implementation &quot;androidx.datastore:datastore-preferences-rxjava3:1.0.0&quot;
implementation &quot;io.reactivex.rxjava3:rxandroid:3.0.0&quot;

The example provided with describing comments:

public class MainActivity extends AppCompatActivity {
// Data store object
RxDataStore&lt;Preferences&gt; dataStore =
new RxPreferenceDataStoreBuilder(this, &quot;settings&quot;).build();
// Key for saving integer value
Preferences.Key&lt;Integer&gt; SOME_KEY = PreferencesKeys.intKey(&quot;SOME_KEY&quot;);
@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&#39;s already observed
observeInt(SOME_KEY, value -&gt; runOnUiThread(() -&gt;
Toast.makeText(this, &quot;Observed Value: &quot; + value, Toast.LENGTH_SHORT).show()));
// Wait some time before reading the data as it takes time until it&#39;s stored; 
// so don&#39;t call it here, but on some other event
readInt(SOME_KEY, value -&gt; runOnUiThread(() -&gt;
Toast.makeText(this, &quot;Value: &quot; + 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&lt;Integer&gt; key, int value) {
dataStore.updateDataAsync(prefsIn -&gt; {
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&lt;Integer&gt; key, IntListener listener) {
Flowable&lt;Integer&gt; flowable =
dataStore.data().map(prefs -&gt; prefs.get(key));
flowable.firstOrError().subscribeWith(new DisposableSingleObserver&lt;Integer&gt;() {
@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&lt;Integer&gt; key, IntListener listener) {
Flowable&lt;Integer&gt; flowable =
dataStore.data().map(prefs -&gt; prefs.get(key));
flowable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // AndroidSchedulers requires ` implementation &quot;io.reactivex.rxjava3:rxandroid:3.0.0&quot; `
.subscribe(new FlowableSubscriber&lt;Integer&gt;() {
@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);
}
}

huangapple
  • 本文由 发表于 2020年9月24日 05:45:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/64036701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定