当前位置: 首页 > 工具软件 > Live Query > 使用案例 >

LiveData

终子昂
2023-12-01

LiveData简介

LiveData是一个持有可观察数据的类。不同于常规的观察者模式,LiveData可以感知生命周期,即他遵从其他应用组件的生命周期,比如Activity、Fragment或Service等。因此LiveData可以确保只更新处于前台的应用组件观察者。
LiveData保护一个Observer类声明的观察者对象(observer),如果LiveData所感知的生命周期处于STARTED或RESEMED状态,那么observer就会被置为激活状态。LiveData只通知处于激活态的观察者更新数据。已经注册到LiveData,但是没有激活的观察者不会收到数据变更的通知。
注册观察者需要传入一个LifecycleOwner接口的实例。这样观察者才可以在生命周期处于DESTROY状态时,被取消注册。这对于Activity或Fragment尤其有用,因为他们可以安全的观察LiveData对象,不用担心泄露问题,它们在销毁阶段会立即取消观察者的注册。

LiveData的优势

  1. 确保UI与数据状态保持一致
    LiveData遵从观察者模式。当被观察数据发生变更时,LiveData会通知所有处于激活态的观察者。你可以根据代码逻辑在这些观察者对象中更新UI。
  2. 没有内存泄露问题
    所有观察者都与LifeCycle对象绑定,当它们的相关生命周期结束时,观察者会将自己从观察者Map中移除。
  3. 不会因为后台涮新Activity导致crash
    如果一个Activity进入后台,那么观察者的生命周期就会进入非激活态,这个观察者不会收到任何LiveData的事件。
  4. 无需手动处理生命周期相关事宜
    UI组件只需要关心相关数据即可,无需手动停止或恢复观察者状态,LiveData会自动处理这些事。
  5. 始终保持数据最新
    观察者有非激活态变为激活态时,会立即收到最新的数据。例如,一个Activity由后台切换到前台时,就会收到最新的数据。
  6. 自适应配置信息变更
    如果一个Activity或Fragment由于配置变更导致重新创建,比如横竖屏变换,那么它会立即收到最新的有效数据。

LiveData使用方法

使用步骤如下:

  1. 创建一个LiveData对象,持有一个明确类型的数据变量。通常在ViewModel中创建。
  2. 创建一个Observer对象,实现onChanged()方法,在这个方法中处理LiveData数据变更事件。通常在Activity或Fragment中创建这个对象。
  3. 调用LiveData对象的observe()方法注册观察者对象。这个方法持有一个LifecycleOwner对象,处理生命周期相关事宜。通常在Activity或Fragment中调用observe()方法。

创建LiveData对象

LiveData对象通常存储在ViewModel对象中,通过getter方法访问,如下所示。

public class NameViewModel extends ViewModel {

// Create a LiveData with a String
private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }

// Rest of the ViewModel...
}

观察LiveData对象

示例代码如下所示。

public class NameActivity extends AppCompatActivity {

    private NameViewModel model;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Other code to setup the activity...

        // Get the ViewModel.
        model = new ViewModelProvider(this).get(NameViewModel.class);

        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                nameTextView.setText(newName);
            }
        };

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.getCurrentName().observe(this, nameObserver);
    }
}

更新LiveData对象

LiveData没有公共的方法去更新存储的数据。MutableLiveData类扩展了setValue(T)和postValue(T)这两个公共方法。必须使用这两个方法去更新数据。ssetValue必须在主线程中调用。示例代码如下所示。

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        model.getCurrentName().setValue(anotherName);
    }
});

调用setValue方法会触发观察者对象调用onChanged()方法,并把"John Doe"传给这个方法。

扩展LiveData

示例代码如下所示:

public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

    public StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

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

在这个例子中,价格监听实现类包含如下几个重要方法:

  • onActive()
    当LiveData对象的激活态观察者数量由0变为1时,就调用这个方法。所有需要在这个方法中注册价格监听。
  • onInactive()
    当LiveData对象的激活态观察者数量由0变为1时,就调用这个方法。所有需要在这个方法中移除价格监听。
  • setValue()
    更新LiveData对象的数据,并通知所有激活的观察者。
    StockLiveData类的使用如下所示:
public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(getViewLifeycleOwner(), price -> {
            // Update the UI.
        });
    }
}

LiveData实现数据共享

事实上,LiveData对象可以在多个Activity、Fragment或Service之间共享数据。示例代码如下所示:

public class StockLiveData extends LiveData<BigDecimal> {
    private static StockLiveData sInstance;
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

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

    private StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

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

监听多个LiveData数据源

MediatorLiveData是LiveData的子类,它允许添加多个LiveData数据源,当有一个数据源发生变更时,都会触发MediatorLiveData的所有观察者。如下所示:

MediatorLiveData liveDataMerger = new MediatorLiveData();
liveDataMerger.addSource(liveData1, new Observer<integer>
 () {
       private int count = 1;
 
       @Override public void onChanged(@Nullable Integer s) {
           count++;
           liveDataMerger.setValue(s);
           if (count &gt; 10) {
               liveDataMerger.removeSource(liveData1);
           }
       }
  });

LiveData实现原理

观察者生命周期

observe方法负责建立生命周期绑定关系,并注册观察者,如下所示:

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

LiveData将Observer对象加入mObservers中,数据变更时会遍历这个Map分发最新数据。LifecycleBoundObserver类负责监听应用组件的生命周期变化,如下所示:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

如onStateChanged方法所示,Lifecycle.State为DESTROYED时,移除观察者,其他情况则更改观察者的状态。

数据分发

有两个方法触发数据分发,一个是setValue,在数据变更时触发;一个是ObserverWrapper的activeStateChanged方法,在生命周期变更是触发(例如,从后台切换到前台),就是这个方法确保了应用组件的数据始终是最新的。如下所示:


    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

   @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

    @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

considerNotify方法负责实际的数据分发,如果观察者处于非激活态则不分发数据,否则有最新的数据就会分发到观察者,即调用onChanged((T) mData)方法。

 类似资料: