Android Jetpackコンポーネント(4つ)LiveData

Android Jetpackコンポーネントシリーズの記事:
Android Jetpackコンポーネント(1 )ライフサイクルAndroid Jetpackコンポーネント(
2)ナビゲーション
Android Jetpackコンポーネント(3)ViewModel
Android Jetpackコンポーネント(4)LiveData
Android Jetpackコンポーネント(5)Room
Android JetPackコンポーネント(6)DataBinding
Android Jetpackコンポーネント(7)Android Jetpackコンポーネントのページング
(8)WorkManager

第一言語

ViewModelは、ライフサイクルに焦点を当てた方法でインターフェース関連のデータを保存および管理します。データが変更されると、インターフェースを介してページに通知できます。ただし、通知するデータが多い場合、定義するのは非常に冗長です。多数のインターフェース。このため、Jetpackはこの問題を解決して開発プロセスを簡素化するLiveDataコンポーネントを提供します。
LiveDataは、監視可能なデータストレージクラスです。これはデータコンテナであり、データが監視可能になるようにデータをパッケージ化し、データが変更されたときに監視者に通知することができます。
LiveDataは、他のアプリケーションコンポーネントのライフサイクルを(例えば、以下のライフサイクルの意識を持ってActivityFragmentまたはService)。この認識機能により、LiveDataは、アクティブなライフサイクル状態にあるアプリケーションコンポーネントのオブザーバーのみを更新します。

利点

  1. インターフェイスがデータ状態に準拠していることを確認します
    。LiveDataはオブザーバーパターンに従います。データが変更されると、LiveDataはオブザーバーオブジェクトに通知します。アプリケーションデータが変更されるたびにインターフェイスを更新する必要はありません。
  2. メモリリークは発生しません
    。LiveDataはLifeCycleオブジェクトにバインドされ、関連するライフサイクルが破棄された後にクリーンアップされます。
  3. アクティビティの停止が原因でクラッシュすることはありません。
    オブザーバーのライフサイクルが非アクティブである場合(リターンスタックなどActivity)、LiveDataイベントを受信しません。
  4. ライフサイクルを手動で処理する必要はありません。
    インターフェイスコンポーネントは、関連するデータのみを監視し、監視を停止または再開しません。LiveDataは、監視中に関連するライフサイクル状態の変化を認識できるため、これらすべての操作を自動的に管理します。
  5. データは常に最新です。
    ライフサイクルが非アクティブになると、再びアクティブになったときに最新のデータを受信します。たとえば、バックグラウンドにActivity入ると、フロントデスクに戻った直後に最新のデータを受信します。
  6. 適切な構成は
    、構成の変更(デバイスのローテーションなど)のために再作成されたActivity場合、またはFragment最新の利用可能なデータをすぐに受信する場合に変更されます
  7. 共有リソース
    シングルトンパターンを使用してLiveDataを拡張およびカプセル化し、アプリケーションで共有できるようにします。

頼る

    implementation 'androidx.lifecycle:lifecycle-livedata:2.3.0'
    //包含了 viewmodel 和 livedata,lifecycle-extensions 中的 API 已弃用
    //implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

使用する

LiveDataは抽象クラスであり、直接使用することはできませんMutableLiveData通常、LiveDataはその直接のサブクラスですLiveData + ViewModelを使用してカウンターの例を完成させます。

public class HomeViewModel extends ViewModel {
    
    
    //value字段用MutableLiveData包装,通常在ViewModel类中完成
    private MutableLiveData<Integer> value;

    public MutableLiveData<Integer> getCurrentValue() {
    
    
        if (value == null) {
    
    
            value = new MutableLiveData<>();
            value.setValue(0);
        }

        return value;
    }
}

LiveDataを定義したら、それを使用してViewModelとページ間の通信を完了する必要があります。

 HomeViewModel homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
 MutableLiveData<Integer> currentValue = homeViewModel.getCurrentValue();

 currentValue.observe(this, new Observer<Integer>() {
    
    
            @Override
            public void onChanged(Integer integer) {
    
    
                textView.setText(String.valueOf(integer));
            }
 });
 button.setOnClickListener(view -> {
    
    
            homeViewModel.addValue();
 });

このページでは、LiveData.observe()LiveDataによってパッケージ化されたデータを監視することで、非UIスレッドおよびUIスレッドで使用されるLivedatapostValue()またはLivedataを介しsetValue()てデータ変更することもできます。更新されたページのLiveDataオブジェクトは、または保存されるのではなく、ViewModelに保存されます。postValue()setValue()
ActivityFragment

 public void addValue() {
    
    
        if (value.getValue() != null) {
    
    
            value.setValue(value.getValue() + 1);
        }
 }

通常、LiveDataは、データが変更されたときにのみ更新を送信し、アクティブなオブザーバーにのみ送信します。例外は、オブザーバーが非アクティブ状態からアクティブ状態に変化した場合です。さらに、オブザーバーが2回目に非アクティブ状態からアクティブ状態に変化した場合、最後にアクティブになったときから値が変更された場合にのみ、オブザーバーは更新を受け取ります。

LiveDataを拡張する

LiveDataの利点の1つは、リソースを共有し、LiveDataクラスのカスタムシングルトンを実装することです。

public class LiveDataUtil extends LiveData<Integer> {
    
    

    private static LiveDataUtil sInstance;
    private LiveDataUtil manager;

    private SimplePListener listener = new SimpleListener() {
    
    
        @Override
        public void onPriceChanged(Integer value) {
    
    
            setValue(value);
        }
    };

    @MainThread
    public static LiveDataUtil getInstance(String symbol) {
    
    
        if (sInstance == null) {
    
    
            sInstance = new LiveDataUtil(symbol);
        }
        return sInstance;
    }

    private LiveDataUtil(String symbol) {
    
    
        manager = new LiveDataUtil(symbol);
    }

    @Override
    protected void onActive() {
    
    
        manager.requestUpdates(listener);
    }

    private void requestUpdates(SimpleListener listener) {
    
    
        this.listener = listener;
    }

    @Override
    protected void onInactive() {
    
    
        manager.removeUpdates(listener);
    }

    private void removeUpdates(SimpleListener listener) {
    
    
        this.listener = listener;
    }
}

それを使用Activityか、Fragmentデータを取得します。

LiveDataUtil.getInstance("flag").observe(this, new Observer<Integer>() {
    
    
            @Override
            public void onChanged(Integer integer) {
    
    
                Log.e("yhj", "onChanged: "+integer);
            }
});

LiveDataを変換する

反例では、値の型はIntegerで、Textviewテキストの型は設定されていStringます。型を変更する必要があります。LiveDataはTransformations、RxJava演算子と同様に、LiveData変換を実行するためのクラスを提供します

//aLiveData监听bLiveData内容的变化,变化时将bLiveData转换为相应的内容并通知aLiveData  
liveData = Transformations.map(homeViewModel.getCurrentValue(), String::valueOf);
 
//aLiveData监听bLiveData内容的变化,变化时从bLiveData获取相应的cLiveData,
//添加到aLiveData的监听列表里,即aLiveData同时监听bLiveData和cLiveData,bLiveData的变化只会switch cLiveData,cLiveData变化才会通知aLiveData
aLiveData=Transformations.switchMap(bLiveData, new Function<Integer, LiveData<String>>() {
    
    
            @Override
            public LiveData<String> apply(Integer input) {
    
    
                return cLiveData;
            }
});

複数のLiveDataを組み合わせる

複数のLiveDataを同時に監視し、LiveDataのサブクラスを介してMediatorLiveData実装されるLiveDataの1つが更新されている限り、通知を受け取ります。

MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
mediatorLiveData.addSource(liveData1, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
             mediatorLiveData.setValue(s);
            }
});
mediatorLiveData.addSource(liveData2, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
                mediatorLiveData.setValue(s);
            }
 });

mediatorLiveData.observe(this, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
            }
});

LiveDataはイベントバスを実装します

以下のようなイベントバスを実装するための多くの方法、ありますEventBusによって実装されRxBus RxJavaが以前の2つの記事を参照できます。これらのフレームワークは両方とも、ライフサイクルの特別な処理を必要とします。LiveDataには独自のライフサイクル認識機能があり、データの更新を認識できるため、LiveDataを通じて独自のライフサイクル認識機能を備えたイベントバスフレームワークを実現できます。

public class LiveDataBus {
    
    

    private static class Lazy {
    
    
        static LiveDataBus sLiveDataBus = new LiveDataBus();
    }

    public static LiveDataBus get() {
    
    
        return Lazy.sLiveDataBus;
    }

    private ConcurrentHashMap<String, StickyLiveData> mHashMap = new ConcurrentHashMap<>();

    public StickyLiveData with(String eventName) {
    
    

        StickyLiveData liveData = mHashMap.get(eventName);
        if (liveData == null) {
    
    
            liveData = new StickyLiveData(eventName);
            mHashMap.put(eventName, liveData);
        }
        return liveData;
    }

   
    public class StickyLiveData<T> extends LiveData<T> {
    
    

        private String mEventName;

        private T mStickyData;

        private int mVersion = 0;

        public StickyLiveData(String eventName) {
    
    

            mEventName = eventName;
        }

        @Override
        public void setValue(T value) {
    
    
            mVersion++;
            super.setValue(value);
        }

        @Override
        public void postValue(T value) {
    
    
            mVersion++;
            super.postValue(value);
        }

        public void setStickyData(T stickyData) {
    
    
            this.mStickyData = stickyData;
            setValue(stickyData);
        }

        public void postStickyData(T stickyData) {
    
    
            this.mStickyData = stickyData;
            postValue(stickyData);
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
            observerSticky(owner, observer, false);
        }

        public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
    
    
            super.observe(owner, new WrapperObserver(this, observer, sticky));
            owner.getLifecycle().addObserver(new LifecycleEventObserver() {
    
    
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    
    
                    if (event == Lifecycle.Event.ON_DESTROY) {
    
    
                        mHashMap.remove(mEventName);
                    }
                }
            });
        }


        private class WrapperObserver<T> implements Observer<T> {
    
    
            private StickyLiveData<T> mLiveData;
            private Observer<T> mObserver;
            private boolean mSticky;

            //标记该liveData已经发射几次数据了,用以过滤老数据重复接收
            private int mLastVersion = 0;

            public WrapperObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {
    
    


                mLiveData = liveData;
                mObserver = observer;
                mSticky = sticky;

                //比如先使用StickyLiveData发送了一条数据。StickyLiveData#version=1
                //那当我们创建WrapperObserver注册进去的时候,就至少需要把它的version和 StickyLiveData的version保持一致
                //用以过滤老数据,否则 岂不是会收到老的数据?
                mLastVersion = mLiveData.mVersion;
            }

            @Override
            public void onChanged(T t) {
    
    
                //如果当前observer收到数据的次数已经大于等于了StickyLiveData发送数据的个数了则return
                if (mLastVersion >= mLiveData.mVersion) {
    
    
                    //但如果当前observer它是关心 黏性事件的,则给他。
                    if (mSticky && mLiveData.mStickyData != null) {
    
    
                        mObserver.onChanged(mLiveData.mStickyData);
                    }
                    return;
                }

                mLastVersion = mLiveData.mVersion;
                mObserver.onChanged(t);
            }
        }

    }
}

LiveDataの原則

LiveDataobserve()方法は、2つのパラメータ、最初のものを受信しLifecycleOwner、第二は、Observerソースコード、ObserverおよびActivityメモリリークを回避するために、知覚LiveDataページのライフサイクルにでき、従って、ライフサイクルに関連が発生することができます。

 @MainThread
 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
    
    
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
    
    
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
  }

もう1つLiveDataがありますがobserveForever()observe()それほど違いはありません。主な違いは、LiveDataが変更されると、ページのステータスに関係なく通知を受信できることです。したがって、使用後removeObserver()にLiveDataの監視停止するように呼び出す必要があります。そうしないと、メモリリークが発生します。

 @MainThread
 public void removeObserver(@NonNull final Observer<? super T> observer) {
    
    
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
    
    
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
 }

おすすめ

転載: blog.csdn.net/yang_study_first/article/details/115232130