关于android:Android-Jetpack架构组件四之LiveData

44次阅读

共计 11230 个字符,预计需要花费 29 分钟才能阅读完成。

一、LiveData 简介

LiveData 是 Jetpack 架构组件 Lifecycle 库的一部分,是一个可感知生命周期的可察看容器类 (Observable)。与惯例的可察看类不同,LiveData 具备生命周期感知能力,这意味着它具备感知利用组件(如 Activity、Fragment 或 Service)的生命周期的能力,并且 LiveData 仅更新处于沉闷生命周期状态的利用组件观察者。

因而,LiveData 具备如下一些特效。

  • LiveData 是一个持有数据的容器类,它持有的数据是能够被观察者订阅的,当数据发生变化时会告诉观察者,观察者能够是 Activity、Fragment、Service 等对象。
  • LiveData 具备感知观察者的生命周期能力,并且只有当观察者处于激活状态(STARTED、RESUMED)才会接管到数据更新的告诉,在未激活时会主动解除注册观察者,以升高内存透露的危险。
  • 应用 LiveData 保留数据时,因为数据和组件是拆散的,所以当组件被销毁时能够保证数据不会失落。

因而,咱们认为 LiveData 就是一个数据容器,它负责将数据包裹起来,使数据成为被观察者,当数据发生变化时,LiveData 会告诉观察者以便观察者做出响应。

那相比其余的一些观察者技术,如 RxJava 什么的,LiveData 有哪些劣势吗,上面是官网给出的一些长处列举。

  • 确保 UI 界面始终和数据状态保持一致。
  • 不会产生内存透露。观察者绑定到 Lifecycle 对象并在其相干生命周期 destroyed 后自行解除绑定。
  • 不会因为 Activity 进行而产生奔溃。如 Activity 执行 finish 办法后,它就不会收到任何 LiveData 事件。
  • 不再须要手动解决生命周期。UI 组件只需察看相干数据,不须要进行或复原察看,LiveData 会主动治理这些操作,因为 LiveData 能够感知生命周期状态的更改。
  • 数据始终保持最新状态。在生命周期从非激活状态变为激活状态,始终保持最新数据,如后盾 Activity 在返回到前台后能够立刻收到数据的最新状态。
  • 适当的配置更改。当配置产生更改(如屏幕旋转)而重建 Activity / Fragment,它会立刻收到最新的可用数据。
  • 资源共享。LiveData 很适宜用于组件(Activity / Fragment)之间的通信,以及共享数据资源。

二、LiveData 与 ViewModel 的关系

在 Jetpack 架构中,ViewModel 的次要作用是存储各种数据,当然,咱们也能够在 ViewModel 中解决一些数据逻辑。例如,咱们能够在 ViewModel 中对加载的数据进行某些加工操作。

而对页面来说,它并不需要关怀 ViewModel 中的数据逻辑,它只关怀须要展现的数据是什么,并且在数据发生变化时告诉页面数据的变动并做出相应的更新。而 LiveData 的作用就是包装 ViewModel 中数据,并让被观察者可能察看数据的变动。下图是官网 Jetpack 架构的示意图。

三、LiveData 的根本应用

3.1 应用步骤

LiveData 的应用比较简单,次要会波及以下几个步骤:

  • 创立 LiveData 实例以存储某种类型的数据,通常在 ViewModel 中实现。
  • 定义一个具备 onChanged()办法的 Observer 对象,当 LiveData 持有数据发生变化时回调该办法。通常,咱们能够在 UI 控制器类中创立该 Observer 对象,如 Activity 或 Fragment。
  • 通过应用 observe()办法将上述的 LiveData 对象和 Observer 对象关联在一起。这样 Observer 对象就与 LiveData 产生了订阅关系,当 LiveData 数据发生变化时告诉,而在 Observer 更新数据,所以 Observer 通常是 Activity 和 Fragment。

从上述步骤能够看出,LiveData 应用了观察者模式,观察者通常是 UI 控制器,如 Activity 或 Fragment,而被观察者则是 LiveData 包谷的数据对象,当 LiveData 对象持有数据发生变化,会告诉对它订阅的所有处于沉闷状态的订阅者。

3.2 LiveData 应用示例

3.2.1 创立 LiveData 对象

LiveData 是一种可用于任何数据的封装容器,其中包含可实现 Collections 的对象,如 List。LiveData 对象通常存储在 ViewModel 对象中,并可通过 getter 办法进行拜访,如下所示。

public class NameViewModel extends ViewModel {

    private MutableLiveData<String> name;
    public MutableLiveData<String> getName() {if (name == null) {name = new MutableLiveData<String>();
        }
        return name;
    }
}

3.2.2 察看 LiveData 对象

在大多数状况下,咱们能够利用组件的 onCreate() 办法中开始察看 LiveData 对象。并且,LiveData 仅在数据产生更改时才发送更新,并且仅发送给沉闷观察者,如下所示。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private NameViewModel model;
    private TextView nameTV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        nameTV=findViewById(R.id.nameTV);
        model = new ViewModelProvider(this).get(NameViewModel.class);
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {nameTV.setText(newName);
            }
        };
        model.getName().observe(this, nameObserver);
    }
}

当咱们传递 nameObserver 参数的状况下调用 observe() 后,零碎会立刻调用 onChanged(),从而提供 mCurrentName 中存储的最新值,如果 LiveData 对象尚未在 mCurrentName 中设置值,则不会调用 onChanged()。事实上,最简略的 LiveData 应用办法是 MutableLiveData,如下所示。

public class MainActivity extends AppCompatActivity {
   private static final String TAG="MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MutableLiveData<String> mutableLiveData  = new MutableLiveData<>();
        mutableLiveData.observe(this, new Observer<String>() { 
            @Override
            public void onChanged(@Nullable final String s) {Log.d(TAG, "onChanged:"+s);
            }
        });
        mutableLiveData.postValue("Android 利用开发实战");
    }
}

3.2.3 更新 LiveData 对象

LiveData 自身没有公开可用的办法来更新存储的数据,如果须要批改 LiveData 的数据,能够应用 MutableLiveData 类将公开 setValue(T) 和 postValue(T) 办法。通常状况下会在 ViewModel 中应用 MutableLiveData,而后 ViewModel 只会向观察者公开不可变的 LiveData 对象,如下所示。

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

3.2.4 扩大 LiveData

如果观察者的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于沉闷状态。以下示例代码阐明了如何扩大 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);
        }
    }
    

在下面的示例中,咱们首先建设一个 StockLiveData 并继承自 LiveData,并重写了 onActive 和 onInactive 两个重要办法。

  • onActivite():当有沉闷状态的订阅者订阅 LiveData 时会回调该办法,意味着须要在这里监听数据的变动。
  • onInactive():当没有沉闷状态的订阅者订阅 LiveData 时会回调该办法,此时没有必要放弃 StockManage 服务象的连贯。
  • setValue():留神到 value=price 这里是调用了 setValue(price)办法,通过该办法更新 LiveData 的值,进而告诉处于沉闷状态的订阅者。

此时,LiveData 会认为订阅者的生命周期处于 STARTED 或 RESUMED 状态时,该订阅者是沉闷的,那么如何应用 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.});
        }
    }
   

以 Fragment 作 LifecycleOwner 的实例传递到 observer()办法中,这样就将 Observer 绑定到领有生命周期的拥有者。因为 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);
        }
    }
    

而后,咱们就能够在 Fragment 中应用它,如下所示。

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {// Update the UI.});
        }
    }
    

3.2.5 转换 LiveData

有时候,咱们心愿在把数据分发给观察者之前进行一些解决,或者返回一个基于已有值的 LiveData 对象的另外一个 LiveData 对象,此时就会用到 Transformations 类。转化 LiveData 时须要用到 Transformations.map()和 Transformations.switchMap()等办法。

Transformations.map()

例如,上面是应用 Transformations.map()办法解决 LiveData 存储的数据,而后将其传递给上游的示例代码。

    LiveData<User> userLiveData = ...;
    LiveData<String> userName = Transformations.map(userLiveData, user -> {user.name + " " + user.lastName});
    
Transformations.switchMap()

应用 Transformations.switchMap()办法同样能够扭转 LiveData 上游的后果,但传递给 switchMap()函数的必须是一个 LiveData 对象,如下所示。

    private LiveData<User> getUser(String id) {...;}

    LiveData<String> userId = ...;
    LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
    

不过,这种转换形式是惰性的,也就是只有 Observer 来订阅数据的时候,才会进行转换。因而,当在 ViewModel 中应用一个 Lifecycle 对象,这种转换是一种很好的解决方案。例如,假如您有一个界面组件,该组件承受地址并返回该地址的邮政编码,那么咱们能够应用 switchMap()办法进行转化。

    class MyViewModel extends ViewModel {
        private final PostalCodeRepository repository;
        private final MutableLiveData<String> addressInput = new MutableLiveData();
        public final LiveData<String> postalCode =
                Transformations.switchMap(addressInput, (address) -> {return repository.getPostCode(address);
                 });

      public MyViewModel(PostalCodeRepository repository) {this.repository = repository}

      private void setInput(String address) {addressInput.setValue(address);
      }
    }
    

四、LiveData 工作原理

通过后面的介绍,咱们晓得 LiveData 是一个可察看的数据持有者,并且它是具备组件生命周期感知能力的,那它是如何察看组件生命周期变动的呢?同时,LiveData 仅更新处于沉闷生命周期状态的利用组件观察者,也即是说 LiveData 并不会告诉所有的观察者,它只会告诉处于沉闷状态的观察者,那么它是如何做到这一点的呢?

LiveData 生命周期变动察看

后面介绍 LiveData 用法的时候提到,首先,咱们创立 LiveData 实例,而后调用 LiveData 的 observe 办法来注册观察者,将 ViewModel 和 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);
    }

能够发现,observe 首先会判断组件以后的状态,如果状态为 DESTROYED,那么间接 return,这阐明 DESTROYED 状态的组件是不容许注册的。而后,新建一个 LifecycleBoundObserver 包装类,将 owner 和 observer 传了进去。接下来,将 observer 和 LifecycleBoundObserver 存储到 SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers 中,留神,此处应用的是 putIfAbsent 办法,接下来对传入的值进行判断,如果传入 key 对应的 value 曾经存在,就返回存在的 value,不进行替换,如果不存在就增加 key 和 value,返回 null。

最初,通过 owner.getLifecycle().addObserver() 办法将 LifecycleBoundObserver 增加到 Lifecycle 中实现注册,这样解决之后 LiveData 就有了察看组件生命周期变动的能力。

LifecycleBoundObservers

LifecycleBoundObservers 是 LiveData 的外部类,源码如下。

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) {if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

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

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

LifecycleBoundObserver 实现了 GenericLifecycleObserver 接口,当组件状态发生变化时,会调用 onStateChanged 办法,当组件处于 DESTROYED 状态时,会调用 removeObserver 办法移除 observer。

而 LifecycleBoundObserver 继承了 ObserverWrapper 类,须要重写 shouldBeActive 办法,用于判断以后传入的组件的状态是否是 Active 状态,即处于 STARTED 和 RESUMED 状态。

ObserverWrapper

ObserverWrapper 是 Observer 的包装类,LiveData 的生命周期状态监听 activeStateChanged 办法就定义在抽象类 ObserverWrapper 中,源码如下。

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

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

      abstract boolean shouldBeActive();

      boolean isAttachedTo(LifecycleOwner owner) {return false;}

      void detachObserver() {}

      void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}
          mActive = newActive;
          boolean wasInactive = LiveData.this.mActiveCount == 0;
          LiveData.this.mActiveCount += mActive ? 1 : -1;
          if (wasInactive && mActive) {onActive();
          }
          if (LiveData.this.mActiveCount == 0 && !mActive) {onInactive();
          }
          if (mActive) {dispatchingValue(this);
          }
      }
  }

activeStateChanged()办法会依据 Active 状态和处于 Active 状态的组件的数量,来对 onActive 办法和 onInactive 办法进行回调,咱们能够应用这两个办法拓展 LiveData 对象。如果生命周期状态是 Active 状态,那么会调用 dispatchingValue 办法。

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

mDispatchingValue 用于标记以后是否处于散发状态中,如果处于散发状态就会进行状态的散发,并最终调用 considerNotify 办法进行音讯的散发,代码如下所示。

private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {return;}
    if (!observer.shouldBeActive()) {observer.activeStateChanged(false); 
        return;
    }
    if (observer.mLastVersion >= mVersion) {return;}
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData); 
}

considerNotify 办法中做了屡次的判断,首先,判断 ObserverWrapper 的 mActive 值如果不为 true 就间接 return。而后,判断以后 observer 对应组件的状态是不是 Active,如果不是就会再次调用 activeStateChanged 办法并传入 false,其办法外部会再次判断是否执行 onActive 办法和 onInactive 办法回调。如果判断条件都满足就持续调用 Observer 的 onChanged 办法,这个办法正是应用 LiveData 的 observe 办法的回调。

正文完
 0