LiveData値のnull可能性を強制する方法はありますか?デフォルトのObserver実装には@Nullableアノテーションがあり、IDEが値がnullの可能性があるため手動で確認する必要があることを示唆しています。
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(@Nullable T t);
}
できることはいくつかありますが、null
をLiveData
に渡さないようにするのはあなたの責任です。それに加えて、すべての「解決策」は警告の抑制であり、危険である可能性があります(null値を取得した場合、それを処理できず、Android Studioは警告しません君は)。
あなたは付け加えられます assert t != null;
。アサートはAndroidでは実行されませんが、Android Studioはそれを理解します。
class PrintObserver implements Observer<Integer> {
@Override
public void onChanged(@Nullable Integer integer) {
assert integer != null;
Log.d("Example", integer.toString());
}
}
警告を抑制する注釈を追加します。
class PrintObserver implements Observer<Integer> {
@Override
@SuppressWarnings("ConstantConditions")
public void onChanged(@Nullable Integer integer) {
Log.d("Example", integer.toString());
}
}
これは私のインストールAndroid Studioでも機能しますが、機能しない場合がありますが、@Nullable
実装からの注釈:
class PrintObserver implements Observer<Integer> {
@Override
public void onChanged(Integer integer) {
Log.d("Example", integer.toString());
}
}
Androidでこれを使用できる可能性は低いですが、純粋にJavaの観点から見ると、新しいインターフェイスを定義して、デフォルトのメソッドにnullチェックを追加できます。
interface NonNullObserver<V> extends Observer<V> {
@Override
default void onChanged(@Nullable V v) {
Objects.requireNonNull(v);
onNonNullChanged(v);
// Alternatively, you could add an if check here.
}
void onNonNullChanged(@NonNull V value);
}
Kotlinを使用する場合、拡張機能を使用して、より優れた非null監視関数を作成できます。それに関する記事があります。 https://medium.com/@henrytao/nonnull-livedata-with-kotlin-extension-26963ffd03
LiveData
クラスもラップする必要があるため、データを設定するコードを制御できる場合にのみ、安全に実行できます。このようにして、データ設定メソッドは@NonNull
で保護され、Observer
に到達する前にデータが既にチェックされていることを確認できます。
LiveData
クラスをラップします。
public class NonNullMutableLiveData<T> extends MutableLiveData<T> implements NonNullLiveData<T> {
private final @NonNull T initialValue;
public NonNullMutableLiveData(@NonNull T initialValue) {
this.initialValue = initialValue;
}
@Override
public void postValue(@NonNull T value) {
super.postValue(value);
}
@Override
public void setValue(@NonNull T value) {
super.setValue(value);
}
@NonNull
@Override
public T getValue() {
//the only way value can be null is if the value hasn't been set yet.
//for the other cases the set and post methods perform nullability checks.
T value = super.getValue();
return value != null ? value : initialValue;
}
//convenience method
//call this method if T is a collection and you modify it's content
public void notifyContentChanged() {
postValue(getValue());
}
public void observe(@NonNull LifecycleOwner owner, @NonNull NonNullObserver<T> observer) {
super.observe(owner, observer.getObserver());
}
}
不変として公開するためのインターフェースを作成します。
public interface NonNullLiveData<T> {
@NonNull T getValue();
void observe(@NonNull LifecycleOwner owner, @NonNull NonNullObserver<T> observer);
}
最後に、Observer
をラップします。
//not implementing Observer<T> to make sure this class isn't passed to
//any class other than NonNullMutableLiveData.
public abstract class NonNullObserver<T> {
public Observer<T> getObserver() {
return new ActualObserver();
}
public abstract void onValueChanged(@NonNull T t);
private class ActualObserver implements Observer<T> {
@Override
public void onChanged(@Nullable T t) {
//only called through NonNullMutableLiveData so nullability check has already been performed.
//noinspection ConstantConditions
onValueChanged(t);
}
}
}
これで、次のようなデータを作成できます。
class DataSource {
private NonNullMutableLiveData<Integer> data = new NonNullMutableLiveData<>(0);
public NonNullLiveData<Integer> getData() {
return data;
}
}
次のように使用します。
dataSource.getData().observe(this, new NonNullObserver<Integer>() {
@Override
public void onValueChanged(@NonNull Integer integer) {
}
});
完全にnull
安全です。
fun <T> LiveData<T>.observeNonNull(owner: LifecycleOwner, observer: (t: T) -> Unit) {
this.observe(owner, Observer {
it?.let(observer)
})
}
ライブラリ自体からのnull値を処理するには、追加の作業を行う必要があります。
たとえば、Roomの@Dao
からLiveData
を返すと、次のようになります。
@Dao interface UserDao {
@get:Query("SELECT * FROM users LIMIT 1")
val user: LiveData<User>
}
そして、user
ライブデータを観察します。ユーザーがいない場合は、onChanged
コールバックをnull
値で呼び出します。