LiveData 简单使用

概述

LiveData是一种类,持有可被观察的数据。

LiveData是一个可以被观察的数据持有类,它可以感知并遵循Activity、Fragment或Service等组件的生命周期。正是由于LiveData对组件生命周期可感知特点,因此可以做到仅在组件处于生命周期的激活状态时才更新UI数据。

LiveData 的优点

  • UI 和实时数据保持一致,因为LiveData采用的是观察者模式,这样一来就可以在数据发生改变时获得通知,更新UI。
  • 避免内存泄漏,观察者被绑定到组件的生命周期上,当被绑定的组件销毁(destroy)时,观察者会立刻自动清理自身的数据。
  • 不会再产生由于 Activity 处于 stop 状态而引起的崩溃,例如:当Activity处于后台状态时,是不会收到LiveData任何事件的。
  • 不需要再解决生命周期带来的问题,LiveData可以感知被绑定的组件的生命周期,只有在活跃状态才会通知数据变化。
  • 实时数据刷新,当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据。
  • 解决Configuration Change问题,在屏幕发生旋转或者被回收再次启动,立刻就能收到最新的数据。

使用

首先是在build.gradle里面添加

// ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
// alternatively, just ViewModel
    implementation "android.arch.lifecycle:viewmodel:2.0.0"
// alternatively, just LiveData
    implementation "android.arch.lifecycle:livedata:2.0.0"

创建LiveData对象

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * created by EDZ
 * on 2020/5/22
 */
public class TestViewModel extends ViewModel {

    private MutableLiveData<String> mNameEvent = new MutableLiveData<>();

    public MutableLiveData<String> getNameEvent(){
        return mNameEvent;
    }
}

观察LiveData对象

   public class MainActivity extends AppCompatActivity {

    private TestViewModel testViewModel ;
    private String TAG = "MainActivity";

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

        testViewModel = new ViewModelProvider(this).get(TestViewModel.class);
        MutableLiveData<String> nameEvent = testViewModel.getNameEvent();
        nameEvent.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                Log.i(TAG, "onChanged: s = " + s);
            }
        });
        testViewModel.getNameEvent().postValue("name");

    }

}

更新LiveData对象

提供setValue(T)、postValue(T)用于更新值

testViewModel.getNameEvent().postValue("name");

调用setValue()或者postValue()都会调用所有观察者的onChanged()方法

因此LiveData setValue的时候也需要在主线程中。如果想在子线程中改变LiveData的值,可以调用postValue(T) 方法来更新 LiveData 对象。

使用 LiveData 构建数据通信总线 LiveDataBus

LiveDataBus 的组成

  • 消息
    消息可以是任何的Object,可以定义不同类型的消息,如Boolean、String。也可以定义自定义类型的消息。

  • 消息通道
    LiveData扮演了消息通道的角色,不同的消息通道用不同的名字区分,名字是String类型的,可以通过名字获取到一个LiveData消息通道。

  • 消息总线
    消息总线通过单例实现,不同的消息通道存放在一个HashMap中。

  • 订阅
    订阅者通过getChannel获取消息通道,然后调用observe订阅这个通道的消息。

  • 发布
    发布者通过getChannel获取消息通道,然后调用setValue或者postValue发布消息。

LiveDataBus的实现

使用这个LiveDataBus的过程中,订阅者会收到订阅之前发布的消息。

public final class LiveDataBus {
 
    private final Map<String, MutableLiveData<Object>> bus;
 
    private LiveDataBus() {
        bus = new HashMap<>();
    }
 
    private static class SingletonHolder {
        private static final LiveDataBus DATA_BUS = new LiveDataBus();
    }
 
    public static LiveDataBus get() {
        return SingletonHolder.DATA_BUS;
    }
 
    public <T> MutableLiveData<T> getChannel(String target, Class<T> type) {
        if (!bus.containsKey(target)) {
            bus.put(target, new MutableLiveData<>());
        }
        return (MutableLiveData<T>) bus.get(target);
    }
 
    public MutableLiveData<Object> getChannel(String target) {
        return getChannel(target, Object.class);
    }
}

注册订阅:

 LiveDataBus.get().getChannel("key_test", String.class)
                .observe(this, new Observer<String>() {
                    @Override
                    public void onChanged(@Nullable String string) {
                        Log.d("LiveDataBus",s)}
                });

发送消息:

LiveDataBus.get().getChannel("key_test").setValue("Hello LiveDataBus");

防止订阅者会收到订阅之前发布的消息

创建类LiveDataBus (由于 T 会有冲突前面加上了? super)

public final class LiveDataBus {

    private final Map<String, BusMutableLiveData<Object>> bus;

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    private static class SingletonHolder {
        private static final LiveDataBus DEFAULT_BUS = new LiveDataBus();
    }

    public static LiveDataBus get() {
        return SingletonHolder.DEFAULT_BUS;
    }

    public <T> MutableLiveData<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new BusMutableLiveData<>());
        }
        return (MutableLiveData<T>) bus.get(key);
    }

    public MutableLiveData<Object> with(String key) {
        return with(key, Object.class);
    }

    private static class ObserverWrapper<T> implements Observer<T> {

        private Observer<T> observer;

        public ObserverWrapper(Observer<T> observer) {
            this.observer = observer;
        }

        @Override
        public void onChanged(@Nullable T t) {
            if (observer != null) {
                if (isCallOnObserve()) {
                    return;
                }
                observer.onChanged(t);
            }
        }

        private boolean isCallOnObserve() {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            if (stackTrace != null && stackTrace.length > 0) {
                for (StackTraceElement element : stackTrace) {
                    if ("android.arch.lifecycle.LiveData".equals(element.getClassName()) &&"observeForever".equals(element.getMethodName())) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    private static class BusMutableLiveData<T> extends MutableLiveData<T> {

        private Map<Observer, Observer> observerMap = new HashMap<>();

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            super.observe(owner, observer);
            try {
                hook(observer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void observeForever(@NonNull Observer<? super T> observer) {
            if (!observerMap.containsKey(observer)) {
                observerMap.put(observer, new ObserverWrapper(observer));
            }
            super.observeForever(observerMap.get(observer));
        }

        @Override
        public void removeObserver(@NonNull Observer<? super T> observer) {
            Observer realObserver = null;
            if (observerMap.containsKey(observer)) {
                realObserver = observerMap.remove(observer);
            } else {
                realObserver = observer;
            }
            super.removeObserver(realObserver);
        }

        private void hook(@NonNull Observer<? super T> observer) throws Exception {
            //get wrapper's version
            Class<LiveData> classLiveData = LiveData.class;
            Field fieldObservers = classLiveData.getDeclaredField("mObservers");
            fieldObservers.setAccessible(true);
            Object objectObservers = fieldObservers.get(this);
            Class<?> classObservers = objectObservers.getClass();
            Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            if (objectWrapper == null) {
                throw new NullPointerException("Wrapper can not be bull!");
            }
            Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
            Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
            fieldLastVersion.setAccessible(true);
            //get livedata's version
            Field fieldVersion = classLiveData.getDeclaredField("mVersion");
            fieldVersion.setAccessible(true);
            Object objectVersion = fieldVersion.get(this);
            //set wrapper's version
            fieldLastVersion.set(objectWrapper, objectVersion);
        }
    }
}

注册订阅:


LiveDataBus.get()
        .with("key_test", String.class)
        .observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                Log.d("LiveDataBus",s)}
        });

发送消息:

LiveDataBus.get().with("key_test").setValue("Hello LiveDataBus");

总结

订阅者可以订阅某个消息通道的消息,发布者可以把消息发布到消息通道上。利用LiveDataBus,不仅可以实现消息总线功能,而且对于订阅者,他们不需要关心何时取消订阅,极大减少了因为忘记取消订阅造成的内存泄漏风险。

你可能感兴趣的:(Android,android,安卓)