Android LifeCycle 使用以及应用分析

2021-01-03  本文已影响0人  虞_18bd

在我最近编写的项目中,始终贯穿整个事件流的组件,可能就是LifeCycle了,在我眼里,它就像是个通用化的UI生命周期管理对象,在Android View层的生命周期方法被调用时,它可以给所有注册过它的方法发送生命周期事件,然后由你决定是否进行处理。

那么问题来了,这不就是接口+观察者模式就可以实现么?那样它看起来并不像它本身那么酷啊。

话不多说,先上使用场景

例子1 来自我们经典的sunflower

// GalleryFragment.kt   
private fun search(query: String) {
    // Make sure we cancel the previous job before creating a new one
    searchJob?.cancel()
    searchJob = lifecycleScope.launch {  // 这里可以看成是绑定了View生命周期的线程,一旦View生命停止,它也将被释放
        viewModel.searchPictures(query).collectLatest {   // 执行的任务
            adapter.submitData(it)
        }
    }
}

可能你会特别蒙蔽,不急,我们直接 进入lifecycleScope中看看

// LifecycleOwner.kt
val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope get() = lifecycle.coroutineScope
// 上面又是kotlin无比装逼的写法 但是可以看出来 返回的是LifecycleCoroutineScope

// Lifecycle.kt
val Lifecycle.coroutineScope: LifecycleCoroutineScope  // ok 返回的就是我了
    get() {
        while (true) {
            val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?  
            if (existing != null) {
                return existing
            }
            val newScope = LifecycleCoroutineScopeImpl(    // 如果没有这个任务 就新建任务
                this,
                SupervisorJob() + Dispatchers.Main.immediate
            )
            if (mInternalScopeRef.compareAndSet(null, newScope)) {   // 这个方法 CAS 芜湖, 把新加的注册进列表
                newScope.register()
                return newScope
            }
        }
    }

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
AtomicReference<Object> mInternalScopeRef = new AtomicReference<>(); // 看到这个Java老哥不会陌生了把,CAS原子操作 看到它就会不自然的想到unsafe =。= (老面试哥的职业病)

internal class LifecycleCoroutineScopeImpl(  //  由我来实现 协程(还是想吐槽,携程是不是给了kotlin广告费)+ View的生命周期绑定
    override val lifecycle: Lifecycle,
    override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
    init {
        // in case we are initialized on a non-main thread, make a best effort check before
        // we return the scope. This is not sync but if developer is launching on a non-main
        // dispatcher, they cannot be 100% sure anyways.
        if (lifecycle.currentState == Lifecycle.State.DESTROYED) { // 生命周期被销毁
            coroutineContext.cancel() // 协程取消 
        }
    }

    fun register() {
        launch(Dispatchers.Main.immediate) {
            if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
                lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
            } else {
                coroutineContext.cancel()
            }
        }
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
            lifecycle.removeObserver(this)
            coroutineContext.cancel()
        }
    }
}

上面就是LifeCycle在协程生命周期上的管理体现(google你为什么不早不做,想起了当年被生命周期支配的恐惧)

例子2:来自自己的项目

首先要说明一下,Android在RxJava + RxAndroid的使用中,内存泄漏是很常见的问题,因为异步任务本身是不会去感知你View的生命周期的,我自己项目中使用的是autoDispose

三方框架实现了RxJava、RxAndroid任务对LifeCycle的绑定

// 登录请求
RxView.clicks(mDataBinding.loginBtn)
        .subscribeOn(AndroidSchedulers.mainThread())
        .to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this))) // 没错就是我 我绑定了LifecycleOwner
        .subscribe(unit ->
                PermissionTools.requestPermission(this, () ->             //                       校验读写权限
                                mViewModel.Login(mDataBinding.userNameEdt.getText().toString().trim()  //  登录请求
                                        , mDataBinding.passwordEdt.getText().toString().trim())
                        , Permission.READ_PHONE_STATE));

 // 登录信息返回通知
LiveEventBus.get(RequestTags.LOGIN_REQ, BaseResponBean.class)
        .observe(this, bean -> {  // 我也绑定了LifecycleOwner
            Optional.ofNullable(mLoading).ifPresent(builder -> mLoading.getObj().dismiss());  // 取消 Loading
                if (bean.getCode() == 200) { // 登录成功
                    ToastUtil.showToast(LoginActivity.this, "登录成功!");
                    startActivity(new Intent(LoginActivity.this, MainActivity.class));
                    finish();
                } else {                     // 登录失败
                    ToastUtil.showToast(LoginActivity.this, "登录失败:" + TCErrorConstants.getErrorInfo(bean.getCode()));
                    mDataBinding.passwordEdt.setText("");  // 清空密码输入框
                }
        });

以上就是两个十分简单的LifeCycle的实际运用,下面分析一下LifeCycle到底做了些什么。

我们通过AppCompatActivity找到他的父类,FragmentActivity的父类, ComponentActivity

//LifecycleOwner.java
public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

//ComponentActivity.java
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
            
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);   
            
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;  // 我返回的就是LifeCycle
    }        
    ......       
}

//LifecycleRegistry.java 这算是核心类了
public class LifecycleRegistry extends Lifecycle {
    //FastSafeIterableMap 它最重要的特点就是,支持在遍历的过程中删除任意元素,不会触发ConcurrentModifiedException
    //自然 它也无法保证线程安全 这个对象是以模拟Map的形式,存了订阅者key,以及订阅者的状态value
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
    
    //你可以泄漏我Lifecycle 但是你没法泄漏LifecycleOwner 
    private final WeakReference<LifecycleOwner> mLifecycleOwner; 

    /**
     * Current state
     */
    private State mState; // 这个就不用说了吧
    
    // 更新状态
    @MainThread
    public void setCurrentState(@NonNull State state) {
        moveToState(state);
    }
    
    // 开始更新
    private void moveToState(State next) {
        if (mState == next) { // 重复事件 丢弃
            return;
        }
        mState = next; // 本地事件状态更新
        if (mHandlingEvent || mAddingObserverCounter != 0) {  // 如果上一次同步没有进行完 或 表示正在同步新订阅者的数量为0 就不处理了
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;    // 开始同步
        sync();
        mHandlingEvent = false;   // 同步结束
    }    
    
    // 同步所有观察者
    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
        while (!isSynced()) {
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);  // 每次同步只向低等级移动
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);  // 每次同步向高等级移动
            }
        }
        mNewEventOccurred = false;
    }
    
    // 判断是否以及全部同步完成
    private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    }    
}

lifecycle.PNG

看图说话 backwardPass 就是RESUMED 到 DESTROYED 的过程,每次只能变化一次,连续的动作

forwardPass就是INITIALIZED 到 RESUMED 的过程,同样 每次只能变化一次, 连续的动作

这时候问题就来了,为什么要这么做? 而且那个嵌套的判断如何解决在同步的过程中有新的观察者加入的情况

这是可以细化成两个小点

在同步过程中,加入了新观察者

在同步过程中,新状态更变加入

private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {  // 中断机制,如果有新的状态更变或是订阅者出现,上一次同步会被中断
        Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) { 
            pushParentState(observer.mState);   // 入栈
            observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState)); // 回调通知状态更变
            popParentState(); // 出栈
        }
    }
}

private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    while (descendingIterator.hasNext() && !mNewEventOccurred) {// 中断机制,如果有新的状态更变或是订阅者出现,上一次同步会被中断
        Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = downEvent(observer.mState);
            pushParentState(getStateAfter(event));
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

这里又出现了个pushParentState以及popParentState 这个栈又是为了保证什么的呢

为了保证新增的状态不会破坏整个Map的有序性

这时候你会觉得奇怪,有序性?什么有序性

仔细看一下sync就会明白,同步的判断依赖于新加入的订阅者状态肯定新于之前加入的订阅者

private State calculateTargetState(LifecycleObserver observer) {
    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
    //previous代表订阅者的当前状态
    State siblingState = previous != null ? previous.getValue().mState : null;
    //在出现事件嵌套时,栈内不为空,最后加入的那个状态,肯定是最新的状态
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
            : null;
    //mParentStates,它限制了新的订阅者的状态更新晚于前面的订阅者
    return min(min(mState, siblingState), parentState);
}

这应该算是牺牲一部分性能保证有序性的操作

以上就是Lifecycle一次状态更变的大致流程,看起来确实也没有太多东西,一个观察者模式,一套新规则,解决了长年的生命周期管理问题,看来基于业务的开发才是未来的主流

上一篇下一篇

猜你喜欢

热点阅读