精华内容
下载资源
问答
  • LiveData

    2021-01-19 18:02:24
    JetPacket LiveData 本文主要介绍两方面的内容 LiveData简单使用 LiveData的粘包事件原因以及处理方式 LiveData简介 LiveData是可以在给定生命周期内观察到的数据持有者类。这意味着Observer可以配对添加...

    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粘包问题就搞定了。

    展开全文
  • LIvedata

    2019-01-03 10:42:14
    LiveData是一个可被观察的数据持有者类。与常规的Observable不同,LiveData能意识到应用程序组件的生命周期变化,这意味着它能遵守Activity、Fragment、Service等组件的生命周期。这种意识确保LiveData只更新处于...

    LiveData是一个可被观察的数据持有者类。与常规的Observable不同,LiveData能意识到应用程序组件的生命周期变化,这意味着它能遵守Activity、Fragment、Service等组件的生命周期。这种意识确保LiveData只更新处于活跃状态的应用程序组件Observe。

     

    LiveData优点:

    一,保证数据与界面的实时更新

    LiveData采用了观察者模式设计,其中LiveData是被观察者,当数据发生变化时会通知观察者进行数据更新。通过这点,可以确保数据和界面的实时性。

    二,有效避免内存泄漏

    这是因为LiveData能够感知到组件的生命周期,当组件状态处于DESTROYED状态时,观察者对象会被remove

    三,Activity/Fragment销毁掉时不会引起崩溃

    这是因为组件处于非激活状态时,在界面不会收到来自LiveData的数据变化通知。这样规避了很多因为页面销毁之后,修改UI导致的crash

    四,不需要手动处理生命周期

    LiveData能够感知组件的生命周期,所以设置LiveData组件的生命周期状态。

    五,始终能够保持最新数据

    生命周期从非活跃状态切换到活跃状态的时候,能够实时的接收最新的数据。

    六,能够应对配置更改

    由于LiveData保存数据的时候,组件和数据是分离的,所以在配置更改(如横竖屏切换等)的时候,即便组件被重新创建,因为数据还保存在LiveData中,这样也能够做到实时的更新。

    七,资源共享

    单例模式扩展LiveData对象并包装成系统服务,以便在应用程序中进行共享,需要该资源的只需要观察LiveData即可。

    LiveData的数据更新

    LiveData的数据更新有两种方式,第一种就是使用setValue的方式只能在主线程也就是UI线程里面调用,另外一种就是postValue的方式可以在主线程或者子线程里面调用

    MutabeLiveData:继承了LiveDataLiveData是一个抽象类不能直接使用,在子类里面重写了postValuesetValue两个方法;

    合并多个LiveData源

      MediatorLiveData是LiveData的一个子类,帮助您合并多个LiveData源。 在任何原始LiveData源对象改变后,MediatorLiveData对象的Observer会被触发。

    LiveData转换

    您可能想对存储在LiveData对象中的值进行更改后再分配给观察者,或者您可能需要根据另一个LiveData实例返回不同的LiveData实例,Transformations类,它包括支持这些场景

    项目地址

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,563
精华内容 1,425
关键字:

livedata