Android架构组件-LiveData

前言

在使用一个新的组件之前,我们需要了解为什么需要使用它、如何使用、使用过程中的注意事项、可扩展或可提升的地方。当我们深入透彻理解这些后,开发中遇到任何问题都可以迎刃而解。当然需要了解这些内容,我们必须熟悉源码的实现过程,这样才能做到心中有数。

为什么需要使用LiveData

LiveData 是一种可观察的数据存储器。应用中的其他组件可以使用此存储器监控对象的更改,而无需在它们之间创建明确且严格的依赖路径。LiveData 组件还遵循应用组件(如 Activity、Fragment 和 Service)的生命周期状态,并包括清理逻辑以防止对象泄漏和过多的内存消耗

其实单独使用LiveData没有太大的意义,它只是可观察的数据存储器,当数据发送的变化的时候,通知相应的Obserer,再执行相应的操作,默认观察数据需要在UI线程里面完成。LiveData是Android 架构组件的一部分,所以使用方面来讲就应该和其他的组件一起使用,从而达到解耦以及灵活的目的。这里主要和ViewModel结合使用更能体现其价值。LiveData也有其他可替代的选择,比如项目中使用Rxjava就可以继续使用,也不用进行替换。

如何使用

方法一

observe(LifecycleOwer,Observer)模式,和生命周期自动结合使用。


private MutableLiveData userLiveData = new MutableLiveData<>();
private void initObserver(){
    userLiveData.observe(this, new Observer() {
        @Override
        public void onChanged(@Nullable User user) {
            Toast.makeText(getApplicationContext(),user.name,Toast.LENGTH_SHORT).show();
        }
    });
}
private void changeData(){
    User user = new User();
    user.name = "test1";
    //自动切换到主线程中执行
    userLiveData.postValue(user);
    //如果能够确定在主线程可以使用该方法
    //userLiveData.setValue(user);
}
private static class User {
    String name;
}

LiveData的使用还是很简单的,调用observe()方法,然后再数据改变的时候调用postValue()或者setValue()即可,setValue()需要保证调用在UI线程,而postValue()自动切换到UI线程中,其中postValue()也是基于Handler来实现,代码如下:

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}


//ArchTaskExecutor使用DefaultTaskExecutor 的postToMainThread()方法
public class DefaultTaskExecutor extends TaskExecutor {
    //省略部分代码
    ......
    
    @Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

}

使用中注意事项

LiveData的文档中有这样一段注释:

/**
 * LiveData is a data holder class that can be observed within a given lifecycle.
 * This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
 * this observer will be notified about modifications of the wrapped data only if the paired
 * LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
 * {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}. 
 *
 *
 .......
  */

意思是如果使用observe()方法,那么会和LifecycleOwner相关,只有在LifecycleOwner的Lifecycle的状态为STARTED或者RESUMED的情况下才会通知更改。如果Activity A 跳转到 Activity B,那么Activit A的Lifecycle的状态变成了CREATED,那么如果此时Activity A的LiveData发生了变化,是不会回调Observer的。举个应用场景,原生个人信息界面 PersonActivity,展现用户的基本信息;开通会员界面,h5界面。如果用户从PersonActivity跳转到开通会员界面,会员开通成功后,需要通知PersonActivity更新,通常我们需要请求一次接口,获取最新用户数据。而我们又是结合LiveData使用,按照上面的注释,PersonActivity是不是就不能回调Observer?答案是的,但是当我们从H5界面回到PersonActivity的时候,会看到数据刷新了,那么文档的解释有误呢?下面我们从源码层了解其实现原理:

1,在LifecycleBoundObserver中监听了LifeCycle的生命周期变化,当生命周期发生变化时,会执行onStateChanged方法。

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {

.......省略部分.......


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

}

//当Activity 的生命周期onResume()执行后,Lifecyle的STATE为RESUMED
void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    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);
    }
}

//
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, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

//通知更新,只有状态为 active才执行
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;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}


那么为什么要这样设计呢?思考了一下,更主要的目的应该是减少程序的奔溃的发生,如果程序内存不足的情况下,会对后台的资源进行回收,难免会对Activity的资源进行回收,如果我们不加以控制,强制让后台界面做一些更新操作,就会引发空指针异常(像这种问题其实不是特别好定位),导致程序的崩溃,带来不好的用户体验。如果在生命周期的onStart()或者onResume()之后再执行更新操作,就能避免这种空指针的错误。

你可能感兴趣的:(Android高级开发)