LiveData

JetPacket LiveData

本文主要介绍两方面的内容

  1. LiveData简单使用
  2. LiveData的粘包事件原因以及处理方式

LiveData简介

LiveData是可以在给定生命周期内观察到的数据持有者类。这意味着Observer可以配对添加LifecycleOwner,并且只有在配对的LifecycleOwner处于活动状态时,才会向该观察者通知有关包装数据的修改。如果LifecycleOwner状态为STARTED或RESUMED,则将其视为活动状态 。观察者添加 observeForever(Observer)被视为始终处于活动状态,因此将始终收到有关修改的通知。对于这些观察者,您应该手动调用 removeObserver(Observer)。

如果相应的生命周期移至DESTROYED状态,则添加了生命周期的观察者将被自动删除。这对于Activity和Fragment可以安全地观察LiveData而不用担心泄漏,对Activity特别有用:销毁它们时,它们将立即被取消订阅。

另外,当active的数量在0到1之间变化时,LiveData具有onActive()和onInactive()通知方法Observer。这使LiveData在没有任何Activity的观察者的情况下释放任何大量资源。

此类用于保存ViewModel的各个数据字段,但也可用于以解耦方式在应用程序中的不同模块之间共享数据。

LiveData简单使用

LiveData一般会结合LifeCycler和ViewModel使用
这里先创建一个ViewModel

public class NameViewModel extends ViewModel {
	//创建一个可修改的LiveData,数据类型为String
    private MutableLiveData<String> currentName;
    public MutableLiveData<String> getCurrentName(){
        if(currentName==null){
            currentName=new MutableLiveData<>();
        }
        return currentName;
    }
}

在Activity中使用LiveData

public class NameActivity extends AppCompatActivity {

    private NameViewModel model;

    private TextView nameTextView;
    private Button btn;
    private int i=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_name);
        nameTextView=findViewById(R.id.tvText);
        btn=findViewById(R.id.btn);

        //需要一个观察者来观察数据
        Observer observer = new Observer<String>(){
            @Override
            public void onChanged(String s) {
                nameTextView.setText(s);
            }
        };
        //获取到viewmodel
        model= ViewModelProviders.of(this).get(NameViewModel.class);
        //取出livedata完成订阅,
        //此处的this是lifecyclerowner,会自动绑定Activity的生命周期
        model.getCurrentName().observe(this,observer);

        btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String anotherName="jett"+(i++);
                //通过LiveData更新数据,调用setValue或者postValue之后,
                //就会回调Observer的onChange方法
                model.getCurrentName().setValue(anotherName);
            }
        });

    }
}

LiveData的简单使用就介绍完了,总结一下就是分为以下几个步骤:

  1. 创建一个LiveData对象
  2. LiveData对象绑定相应的LifeCyclerOwner和Observer
  3. 调用setValue或者postValue更新数据,数据更新之后,LiveData会自动回调Observer的onChange方法

此处需要注意的是,setValue只能在UI线程调用,postValue是在子线程中调用,有兴趣的可以看源码,postValue最终还是转到UI线程通过setValue使数据更新生效

到这里可能大家会想,那如果有很多种不同类型的数据需要更新,那么是不是需要多个LiveData对象去处理不同的数据,这样写会很麻烦,此处可以考虑使用泛型,将项目中可能要使用到的不同类型的LiveData整合到一起,生成一个LiveDataBus。

public class LiveDataBus {
    //存放订阅者
    private Map<String, MutableLiveData<Object>> bus;
    private static LiveDataBus liveDataBus = new LiveDataBus();

    private LiveDataBus() {
        bus = new HashMap();
    }
    public static LiveDataBus getInstance() {
        return liveDataBus;
    }
    //注册订阅者
    public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
        if(!bus.containsKey(key)){
            bus.put(key,new MutableLiveData<Object>());
        }
        //这里使用强制转换,加上泛型,可以约定LiveData的数据类型
        return (MutableLiveData<T>)bus.get(key);
    }
}

LiveDataBus的使用

public class MainActivity extends AppCompatActivity {

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

    public void click(View view) {
        if (view.getId() == R.id.btn) {
            Intent intent = new Intent(this, NameActivity.class);
            startActivity(intent);
        } else if (view.getId() == R.id.btn2) {
            Intent intent = new Intent(this, TestLiveDataBusActivity.class);
            startActivity(intent);
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        //发送消息
                        LiveDataBus.getInstance().with("data", String.class).postValue("xxx");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    }
}
public class TestLiveDataBusActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedatabus);
        //绑定LifeCyclerOwner和Observer
        //MainActivity中更新数据之后,就会回调此处Observer的onChange方法
        LiveDataBus.getInstance().with("data", String.class)
                    .observe(this, new Observer<String>() {
                        @Override
                        public void onChanged(String s) {
                            if(s!=null)
                            Toast.makeText(TestLiveDataBusActivity.this, s, Toast.LENGTH_SHORT).show();
                        }
                    });
    }
}

LiveData粘包事件

回顾一下LiveData的使用3步骤:

  1. 创建一个LiveData对象
  2. LiveData对象绑定相应的LifeCyclerOwner和Observer
  3. 调用setValue或者postValue更新数据,数据更新之后,LiveData会自动回调Observer的onChange方法

在上面的使用中,你会发现,在MainActivity中先通过startActivity启动TestLiveDataBusActivity,然后在线程中不断更新数据,在一开始更新数据的时候,TestLiveDataBusActivity还没执行声明周期函数onCreate,Observer还没有跟LiveData进行绑定订阅,但是在TestLiveDataBusActivity启动的时候,就会发现收到了之前MainActivity更新的消息。
如果严格按照上面1-2-3的顺序是没有什么疑问,但是目前我们的使用步骤其实是1-3-2,先更新了数据,然后才执行的绑定动作,但是依然收到了数据,这个就有问题了,很多时候,业务有一定的时序行,可能并不需要之前的数据,这样就出问题了。
LiveData的粘包就是只,先发送的数据,然后才绑定的Observer,但是Observer依然收到了回调,那么这个问题是怎么造成的呢?
其实是在setValue的时候,会将更新的值保存在mData这个成员变量中,绑定Observer的时候,调用observe方法,然后一步步最后会根据LifecyclerOwner的生命周期,根据相对应的State,等到发现当前的状态至少是STATED的时候,就去回调Observer的onChange方法
调用流程:
observe[LiveData.java]–>owner.getLifecycle().addObserver(wrapper)–>addObserver[LifecycleRegistry.java]–>statefulObserver.dispatchEvent–>dispatchEvent[LifecycleRegistry.java-ObserverWithState]–>mLifecycleObserver.onStateChanged–>onStateChanged[LiveData.java-LifecycleBoundObserver]–>activeStateChanged–>dispatchingValue–>considerNotify–>observer.mObserver.onChanged((T) mData)

//LiveData.java
@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //注意此处放进mObservers的是LifecycleBoundObserver 
        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;
        }
        //调用lifeCycler的addObserver方法,绑定Observer和LifecyclerOwner
        owner.getLifecycle().addObserver(wrapper);
    }
//LifecycleRegistry.java
@Override
    public void addObserver(@NonNull LifecycleObserver observer) {
    	//初始状态为INITIALIZED
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ......
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        //此处statefulObserver.mState为INITIALIZED
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            //这里开始分发生命周期事件
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        ......
    }

void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            //生命周期更新
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
//LiveData.java
@Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //这里需要注意shouldBeActive()方法
            activeStateChanged(shouldBeActive());
        }
        @Override
        boolean shouldBeActive() {
        	//当前的状态至少是STARTED的时候,才说明Lifecycler是处于Active状态
        	//DESTROYED,INITIALIZED,CREATED,STARTED,RESUMED
        	//也就是说,当前状态只有是STARTED或者RESUMED的时候才是Active
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        void activeStateChanged(boolean newActive) {
        	if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            ......
            //当TestLiveDataBusActivity执行到onStart,onResume的时候,
            //shouldBeActive()方法返回true,那么mActivity为true
            if (mActive) {
                dispatchingValue(this);
            }
        }

	void dispatchingValue(@Nullable ObserverWrapper initiator) {
        ......
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                ......
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    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的onChange方法
        observer.mObserver.onChanged((T) mData);
    }

到这里,LiveData的粘包事件流程就理清楚了

粘包事件处理办法

上面considerNotify方法中有这么个判断条件:

if (observer.mLastVersion >= mVersion) {
            return;
        }

如果能在调用onChange方法之前使if条件命中,那么就可以避免粘包事件。等到绑定完observer之后,再次更新数据时候,setValue中会调用mVersion++,更新mVersion的值,这个时候if条件就不会命中了,那么就可以正常收发数据,而躲过observe绑定订阅之前的数据

此处利用反射,修改observer.mLastVersion的值:

public class LiveDataBusX {
    //存放订阅者
    private Map<String, BusMutableLiveData<Object>> bus;

    private static LiveDataBusX liveDataBus = new LiveDataBusX();

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

    public static LiveDataBusX getInstance() {
        return liveDataBus;
    }

    //注册订阅者,(存入map) Hook前用MutableLiveData
    public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type){
        if(!bus.containsKey(key)){
            bus.put(key,new BusMutableLiveData<Object>());
        }
        return (BusMutableLiveData<T>) bus.get(key);
    }

    public static class BusMutableLiveData<T> extends MutableLiveData<T> {
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            super.observe(owner, observer);
            hook(observer);
        }
        //在这里去改变onChange的流程
        private void hook(Observer<? super T> observer) {
            try {
                //1.得到mLastVersion
                //获取到LiveData的类中的mObservers对象
                Class<LiveData> liveDataClass = LiveData.class;
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                //获取到这个成员变量的对象
                Object mObserversObject = mObserversField.get(this);
                //得到map对应的class对象
                Class<?> mObserversClass = mObserversObject.getClass();
                //获取到mObservers对象的get方法
                Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                get.setAccessible(true);
                //执行get方法
                Object invokeEntry=get.invoke(mObserversObject,observer);
                //定义一个空的对象
                Object observerWraper=null;
                if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
                    observerWraper=((Map.Entry)invokeEntry).getValue();
                }
                if(observerWraper==null){
                    throw new NullPointerException("observerWraper is null");
                }
                //得到ObserverWrapper的类对象  编译擦除问题会引起多态冲突所以用getSuperclass
                Class<?> superclass = observerWraper.getClass().getSuperclass();
                Field mLastVersion = superclass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                //2.得到mVersion
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);
                //3.把mVersion的数据填入到mLastVersion中
                Object mVersionValue=mVersion.get(this);
                mLastVersion.set(observerWraper,mVersionValue);


            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

}

使用方式:
修改之前MainActivity和TestLiveDataBusActivity的使用方式:

//MainActivity.java
new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        //发送消息
                        LiveDataBusX.getInstance().with("data", String.class).postValue("xxx");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }


                    }
                }
            }.start();
//TestLiveDataBusActivity.java
LiveDataBusX.getInstance().with("data", String.class)
                    .observe(this, new Observer<String>() {
                        @Override
                        public void onChanged(String s) {
                            if(s!=null)
                            Toast.makeText(TestLiveDataBusActivity.this, s, Toast.LENGTH_SHORT).show();
                        }
                    });

这样再次使用,就会发现,在TestLiveDataBusActivity中,调用observe方法之前,LiveData更新的消息没有回调onChange方法,只收到了observe之后的消息更新。
这样LiveData粘包问题就搞定了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值