灵魂组件Lifecycle的生命周期机制详解

news2024/11/17 13:40:54

作者:苏火火

前言

在早期 Andorid 架构中,生命周期的事件监听和状态查询,我们需要自定义一套提供侦测功能的 Activity/Fragment 基类及回调接口,在 Activity/Fragment 的生命周期方法中实现依赖组件的操作,在外部进行事件监听和状态查询。这种模式会导致代码条理性很差而且会扩散错误。

Lifecycle 引入后,可以避免在 Activity/Fragment 生命周期方法内写太多的业务逻辑处理代码,这样可以使我们的业务逻辑更加解耦。有助于您编写出更有条理且往往更精简的代码,此类代码更易于维护。

什么是Lifecycle

Lifecycle 是一个具备宿主生命周期感知能力的组件。它持有组件(Activity/Fragment)生命周期状态信息,并且允许其观察者监听宿主生命周期状态变化

一、Lifecycle的使用

build.gradle 文件中添加依赖:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-common:2.5.1"

使用 Lifecycle 观察宿主状态有三种实现方式。

1.继承LifecycleObserver

第一种是实现 LifecycleObserver 接口,采用注解方式,使用 @OnLifecycleEvent 标记自定义的方法以实现回调。

//1.自定义LifecycleObserver观察者,用注解声明每个方法观察宿主的状态
public class MyLifecycleObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart(@NotNull LifecycleOwner owner) {

    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(@NotNull LifecycleOwner owner) {

    }
}

//2.宿主中注册观察者,观察宿主生命周期状态变化
class MyFragment extends Fragment {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyLifecycleObserver observer = new MyLifecycleObserver();
        getLifecycle().addObserver(observer);
    }
}

实现 LifecycleObserver 接口,只需要在指定方法上面标记注解,来观察宿主的生命周期,注解里面标记着生命周期事件类型就可以了。然后在宿主注册这个 LifecycleObserver,它不需要销毁的时候进行反注册。

2.实现DefaultLifecycleObserver接口

第二种方式:定义一个类,实现 DefaultLifecycleObserver 接口,里面提供了完整的生命周期事件,为所有的生命周期事件都定义了对应的回调方法。它实现了 FullLifecycleObserver 接口,使用了 default 关键字空实现了各个方法。

class MyFullLifeObserver : DefaultLifecycleObserver {

    override fun onCreate(owner: LifecycleOwner) {}

    override fun onStart(owner: LifecycleOwner) {}

    override fun onResume(owner: LifecycleOwner) {}

    override fun onPause(owner: LifecycleOwner) {}

    override fun onStop(owner: LifecycleOwner) {}

    override fun onDestroy(owner: LifecycleOwner) {}
}

使用 DefaultLifecycleObserver 后,就需要把注解实现相关逻辑移除。即使保留注解,由于 Lifecycling 的处理逻辑(系统架构逻辑中所有传入的观察者都会经过 Lifecycling 处理,下面会讲解到),任何 FullLifecycleObserver 的实现类 (即包括DefaultLifecycleObserver) 内部所有的 @OnLifecycleEvent 注解都会失效。

3.实现LifecycleEventObserver

第三种方式:实现 LifecycleEventObserver,它是 LifecycleObserver 的子接口。只有一个 onStateChanged 方法,以 Lifecycle.Event 入参提供事件区分的形式,进行统一方法回调。

interface LifecycleEventObserver : LifecycleObserver {
    // 宿主生命周期变化的事件都会通知到这个方法
    fun onStateChanged(owner: LifecycleOwner?, event: Lifecycle.Event?)
}

//继承自LifecycleEventObserver,复写onStateChanged方法
class MyLifecycleEventObserver : LifecycleEventObserver {
    override fun onStateChanged(owner: LifecycleOwner?, event: Lifecycle.Event?) {
        //需要自行判断Event是onStart还是onStop
    }
}

无论哪一种方法都需要在宿主中注册观察者。推荐使用第二种和第三种方式,第一种不推荐使用。

二、Lifecycle 组件架构

为下面更好深入理解原理,我们先来简单了解下 Lifecycle 组件中几个重要的类:

  • Lifecycle(生命周期) :一个核心抽象类,用于存储有关组件(如 activity/fragment 的生命周期状态的信息,并允许其他对象观察此状态。继承该类的子类,表示本身是一个 具有Android生命周期特性 的对象。

  • LifecycleOwner核心接口,Lifecycle 持有者,该接口的实现类表示能够为外部提供Lifecycle实例。具有 Android 生命周期的类。这些事件可以被自定义组件用来处理生命周期的变化,而不需要在 Activity/Fragment 中实现任何代码。

  • LifecycleRegistry:核心类,Lifecycle 的实现类,可以处理多个观察者。实现 Lifecycle 定义生命周期观察订阅,生命周期查询的方法。还实现了架构中,生命周期变化时触发的自身状态处理和相关对观察者的订阅回调的逻辑。

  • LifecycleObserver:观察者,将一个类标记为生命周期观察者。实现该接口的类,通过注解的方式,可以通过被 LifecycleOwner 类的 addObserver() 方法注册,LifecycleObserver 便可以观察到 LifecycleOwner生命周期事件

  • State :当前生命周期所处的状态

  • Event :当前生命周期改变对应的事件。从框架和 Lifecycle 类分派的生命周期事件。这些事件对应到 activity/fragment 中的回调事件。

LifecyclerOwner、Lifecycle、LifecyleRegistry 和 Observer 的关系如下图:

一般来说宿主代表着 Activity/Fragment,都实现了 LifecyclerOwner 接口;那么每个宿主必须复写 getLifecycle(),并且返回一个 Lifecycle 对象,这个 Lifecycle 对象实际上是LifecycleRegistry,只不过它采用的是面向接口的编程方式,我们对 LifecycleRegistry 注册 Observer 的时候,可以是 LifecycleObserverFullLifecyclerOberverLifecyclerEventObserver

三、Lifecycle 原理剖析

系统框架中,LifecycleOwner 接口的实现类为 ComponentActivityFragment,两者提供的 Lifecycle 对象,是系统框架实现中 Lifecycle 的唯一子类 LifecycleRegistry

1.Fragment是如何实现Lifecycle的

public class Fragment implements LifecycleOwner {
    // 创建LifecycleRegistry 并且把this传递进去
    LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public Lifecycle getLifecycle() {
        //2.复写自LifecycleOwner,所以必须new LifecycleRegistry对象返回
        return mLifecycleRegistry;
    }
    //······
}

Fragment 内 Lifecycle 核心代码片段,实现了 LifecycleOwner 接口,它表示生命周期宿主,持有生命周期(Lifecycle对象),该接口的生命周期的改变会被其注册的观察者 LifecycleObserver 观察到并触发其对应的事件。

必须复写 getLifecycle() 这个方法,返回的实际是 mLifecycleRegistry,说明 LifecycleLifecycleRegistry 的父类,这是一种面向接口的编程思想。

public class Fragment implements LifecycleOwner {
    //······
    void performCreate(Bundle savedInstanceState) {
        //······
        onCreate(savedInstanceState);
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }

    void performStart() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }

    void performResume() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }

    void performPause() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    }

    void performStop() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }

    void performDestroy() {
        mChildFragmentManager.dispatchDestroy();
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        //······
     }
}

我们注册 Lifecycle 的时候,实际上都注册到 LifecycleRegistry 里面去了。通过 handleLifecycleEvent() 分发自己的状态到每个观察者,从而实现观察生命周期实现变化的能力。看起来简单实际上 Lifecycle 在分发生命周期的时候并不简单,所有逻辑重点都在 LifecycleRegistry

Fragment 是如何派发生命周期的?也就是它会在自己生命周期里面,让 LifecycleRegistry 去分发生命周期事件,给每一个观察者。但是 Activity 中并不是这么做的。

2.Activity是如何是实现Lifecycle的

Activity 实现 Lifecycle 的核心源码,需要来到 ComponentActivity 里面,同样也是实现了 LifecycleOwner 接口:

public class ComponentActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    //复写getLifecycle(),返回LifecycleRegistry对象
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //往Activity上添加一个fragment,用以报告生命周期的变化
        //目的是为了兼顾不是继承自AppCompactActivity的场景
        ReportFragment.injectIfNeededIn(this);
    }
}

与上面 Fragment 的实现类似,它实现了 LifecycleOwner,表示一个生命周期的宿主,必须实现 getLifecycle() 方法,返回一个 Lifecycle,也就是 LifecycleRegistry

但是在 ComponentActivity 里面并没有在它的每个生命周期方法里面把它的状态分发给一个观察者,但是在 onCreate() 方法里面调用 ReportFragment.injectIfNeededIn(this) 这种做法实际上是往自己里面添加了一个不可见的 Fragment,专门用于报告分发给每个观察者。

public class ReportFragment extends Fragment {
    public static void injectIfNeededIn (Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            // API 29 以上可以直接注册正确的生命周期回调
            activity.registerActivityLifecycleCallbacks(
                new LifecycleCallbacks ()
            );
        }
        // 兼容API 29之前的,需要支持直接继承Activity的,使用Fragment来正确获得生命周期事件
        android.app.FragmentManager manager = activity . getFragmentManager ();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment (), REPORT_FRAGMENT_TAG).commit();
            manager.executePendingTransactions();
        }
    }
} 

所以 Activity 事件的分发是依靠 ReportFragment 来完成的。

  • API 29 以下: 主要是通过 ReportFragment 将自身添加到 Activity 中实现。
  • API 29 及以上:Activity 中增加一组 ActivityLifecycleCallbacks 的相关方法,可以直接通过注册 ActivityLifecycleCallbacks 观察生命周期。

ComponentActivity 为什么这么做而不直接在 Activity 内部直接分发呢?主要是为了兼顾不是继承自 AppCompatActivity 的场景。有可能是直接继承自 Activity,然后自己实现了 Lifecycle 接口。

public class ReportFragment extends Fragment {
    // 增加dispatch重载,尝试获取Activity中的LifecycleRegistry并调用 handleLifecycleEvent
    static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }
    // 2.各个生命周期方法里面都调用了dispatch()方法
    @Override
    public void onStart() {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }

    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }
    //······

    // 3.拿到Activity的Lifecycle对象,把当前的事件分发给每个观察者
    private void dispatch(@NonNull Lifecycle.Event event) {
        if (Build.VERSION.SDK_INT < 29) {
            // 在API 29之前从ReportFragment分派事件。
            // 在API 29+上,由reportfragment.injectifneededdin中添加的activitylifecyecallbacks处理
            dispatch(getActivity(), event);
        }
    }
}

为了前向兼容,ReportFragment 依然会被添加到 Activity,并在 dispatch() 中增加过滤避免出现二次调用。

ReportFragment 会在侦测到 Activity 生命周期变化的时候调用 LifecycleRegistry.handleLifecycleEvent() 传入对应的状态。 这时候会有一个类 LifecycleDispatcher:

//挂钩到Activity的回调并进行观察
class LifecycleDispatcher {
    private static AtomicBoolean sInitialized = new AtomicBoolean(false);

    static void init(Context context) {
        ((Application) context.getApplicationContext())
                .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
    }

    static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            // 监听到每个Activity打开的事件
            ReportFragment.injectIfNeededIn(activity);
        }
    }
}

在它的 init() 方法里面调用了 registerActivityLifecycleCallbacks(),这里就能监察到每个 Activity 打开的事件,会再次利用 ReportFragment.injectIfNeededIn(activity),也就是说往每个 Activity 里面注册一个 ReportFragment,用于分发和报告当前宿主的生命周期到每个观察者,它这里是以一个切面编程的方式注入了一个 Fragment 对象,尽管我们是继承子 Activity,只要你实现了 LifecycleOwner 的接口,也能具备生命周期分发的能力。所以 Activity 生命周期分发的功能提取到 ReportFragment 里面,主要是为了不是继承自 AppCompatActivity 的场景。

到这里 Activity/Fragment 各自是如何实现 Lifecycle 能力的已经分析完成。但是无论如何生命周期能力都是依赖 LifecycleRegistry 来完成的。

3.LifecycleRegistry 源码分析

它是 Lifecycle 的实现,可以处理多个观察者。生命周期事件分发都是依靠 LifecycleRegistry 来完成的。先从添加观察者方法开始:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    // 1.初始化状态,当前宿主的状态
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // 2.将observer封装成 ObserverWithState,是一个拥有宿主状态的观察者
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // 添加到Map集合中
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    // 3.计算出它应该到达的状态,也就是当前宿主的状态
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    // 4.在while()循环中,会让当前的观察者的状态从init状态前进到当前宿主的状态
    //Observer的状态与targetState比较,如果小于0说明观察者的状态还没有到达targetState的状态
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        // 5.让Observer的状态前进到targetState
        final Event event = Event.upFrom(statefulObserver.mState);
        // 6. 分发事件
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        popParentState();
        // 从新计算mState
        targetState = calculateTargetState(observer);
    }

    if (!isReentrance) {
        //同步状态
        sync();
    }
}

addObserver(observer) 里面,初始化状态,并且把observer封装成一个ObserverWithState,一个拥有宿主状态的观察者,然后添加到Map集合当中。

这里主要做了四件事:

  1. 初始化状态,将 observer 封装成 ObserverWithState,是一个拥有初始状态的观察者;
  2. 计算出它应该到达的状态,也就是当前宿主的状态;
  3. while 循环会让当前的观察者的状态从 INITIALIZED 状态前进到当前宿主的状态,Observer 的状态小于 targetState 说明观察者的状态还没有到达 targetState 的状态,那么就会让 Observer 的状态前进到 targetState;
  4. Observe 调用 dispatchEvent() 分发事件。

每个步骤都很重要,我们来一一分析:

4.状态与事件

State 是一个枚举,表示宿主的状态,但是宿主的状态和宿主的生命周期不是同一个概念。

public enum State {
    // 宿主的销毁状态,onDestory()之后
    DESTROYED,
    // 宿主的初始状态,onCreate()之前
    INITIALIZED,
    // 宿主的创建状态,onCreate()之后,onStop()之前
    CREATED,
    // 宿主的启动状态,onStart()之后,onPasue()之前
    STARTED,
    // 恢复状态,onResume()之后
    RESUMED;
}

比如宿主切换到后台,会执行 onPause() 方法,那么宿主的状态是什么状态?再从后台切回前台会执行 onStart() 再执行 onResum(),所以切换到后台的时候,执行了 onPause 这个事件,它的状态会变成 STARTED 的状态。可以看到它是没有 PAUSE 状态的。

这里还定义了 Event 事件,一个枚举,表示生命周期事件。它与宿主的生命周期一一对应。

public enum Event {
     //LifecycleOwner的onCreate事件的常量
    ON_CREATE,
     //LifecycleOwner的onStart事件的常量
    ON_START,
     //LifecycleOwner的onResume事件的常量
    ON_RESUME,
     //LifecycleOwner的onPause事件的常量
    ON_PAUSE,
     //LifecycleOwner的onStop事件的常量
    ON_STOP,
     //LifecycleOwner的onDestroy事件的常量
    ON_DESTROY,
     //可以匹配所有事件的常量
    ON_ANY
}

宿主生命周期与宿主状态关系图:

宿主在创建之初肯定是处于 INITIALIZED 状态,执行了 onCreate() 方法之后就会进入 CREATED 状态,接着执行了 onStart() 方法之后就会进入 STARTED 状态,执行了 onResume() 就会进入 RESUMED 状态,这是生命周期前进的过程,生命周期倒退过程同理。这里就是宿主的生命周期状态和事件完整的流程。

5.状态比较和升降级

回到 addObserver() 方法中:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    // 1.获取observer需要设置的初始状态
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // 2.将observer封装成 ObserverWithState,并绑定初始的生命周期状态
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // 添加到Map集合中
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    // 3.计算出它应该到达的目标状态
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    // 4.在while()循环中,会让当前的观察者的状态从init状态前进到目标状态
    //Observer的状态与targetState比较,如果小于0说明观察者的状态还没有到达targetState的状态
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        // 5.让Observer的状态升级到targetState
        final Event event = Event.upFrom(statefulObserver.mState);
        // 6. 分发事件,同步状态
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        popParentState();
        // 重新计算mState
        targetState = calculateTargetState(observer);
    }

    if (!isReentrance) {
        //同步状态
        sync();
    }
}

在初始状态中,只要不是在 onDestory 注册的 Observer,每个观察者的初始状态都是 INITIALIZED 状态。在 while 循环中,会让当前的观察者的状态从 INITIALIZED 状态升级到目标状态,如果观察者的状态小于目标状态,就会通过 Event.upFrom() 方法让生命周期升级。

比如我们在 onResme() 方法中注册一个观察者,那么它会接收到哪几种状态呢?INITIALIZED、ONSTART、ONRESUME 它都会有,这个逻辑就在 while 循环里面,先通过 calculateTargetState(observer) 计算出它应该到达的目标状态,也就是当前宿主的状态,然后会拿 Observer 的状态比较,如果小于0说明观察者的状态还没有到达 targetState 的状态,那么就会让 Observer 的状态升级到 targetState。那么是如何进行升级的呢?

// 计算传入状态升级所对应的事件
public static Event upFrom(@NonNull State state) {
    switch (state) {
        case INITIALIZED:
            return ON_CREATE;
        case CREATED:
            return ON_START;
        case STARTED:
            return ON_RESUME;
        default:
            return null;
    }
}

离开当前的状态到达更高的状态,事件的状态从较低向上升级。在 INITIALIZED 状态中接收的是 on_Create 事件,然后来到 dispatchEvent() 方法里面:

static class ObserverWithState {
    // 当前状态
    State mState;
    // Observer封装
    LifecycleEventObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) {
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }

    //事件分发逻辑
    void dispatchEvent(LifecycleOwner owner, Event event) {
        //根据Event获取目标状态
        State newState = event.getTargetState();
        // 获取最小状态
        mState = min(mState, newState);
        // 状态改变回调
        mLifecycleObserver.onStateChanged(owner, event);
        // 更新当前状态
        mState = newState;
    }
}

会根据 Event 反推出目标状态,在 event.getTargetState() 里面,如果 Event 事件是 ON_CREATE 那么就会到达 State.CREATED 的状态,在调用 mLifecycleObserver.onStateChanged(owner, event) 之后,mState = newState状态就变成新的状态,前进了一步,从 INITIALIZED 状态变成了 CREATED 状态。

// 获取事件目标状态
public State getTargetState() {
    switch (this) {
        // 如果事件是 ON_CREATE或者ON_STOP,那么状态会到达State.CREATED
        case ON_CREATE:
        case ON_STOP:
            return State.CREATED;
        case ON_START:
        case ON_PAUSE:
            return State.STARTED;
        case ON_RESUME:
            return State.RESUMED;
        case ON_DESTROY:
            return State.DESTROYED;
        case ON_ANY:
            break;
    }
}

它在分发事件的时候是根据观察者的状态推导出分发的事件,然后再根据分发的事件推导出观察者的状态,在这个方法执行完后,会再次回到While()循环中,再次进行观察者状态与目标状态比较,当前状态 mState 已经变成 CREATE, 如果 targetState 是 INITIALIZED,那么就实现了状态的升级。

但是如果 targetState 是 RESUME,while循环比较还是小于0的,则会再次调用 Event.upFrom(mState)dispatchEvent() 方法,将状态升级到 STATED,继续循环升级到 RESUME,依此类推,mState = newState状态就变成新的状态 RESUME。直到观察者的状态和宿主的状态达到一致,然后退出While()循环,如下图

  • 添加Observer时,完整的生命周期事件分发

ObserverWithState 被创建之初状态为 INITIALIZED,如果在宿主的 onResume() 生命周期注册一个 Observer,会把宿主的 onCreate,onStart,onResume 都分发给 Observer

直到 Observer 的状态和宿主的状态对齐为止,而不是直接从 INITIALIZED 状态直接分发一个 RESUME 直接到达 RESUME,目的因为我们可以在任何地方注册,并且可以接收到完整的接收事件,从而完成初始化,暂停,释放的工作。

这是添加观察者时的事件分发流程。

6.Lifecycle是如何分发宿主状态的

那么宿主的生命周期变化之后是如何分发给每一个观察者的?

根据上面 Activity/Fragment 源码分析,它会在每个生命周期方法里面执行handleLifecycleEvent(event)event.getTargetState()根据当前的事件推导出每个观察者目标的生命周期状态。

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    enforceMainThreadIfNeeded("handleLifecycleEvent");
    moveToState(event.getTargetState());
}

private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    mState = next;
    mHandlingEvent = true;
    // 同步新状态事件
    sync();
    mHandlingEvent = false;
}

moveToState(next) 里面主要是做一些条件的判断,真正的状态同步是在 sync() 方法里面:

private void sync() {
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    //循环,直到isSynced()同步完成,所有观察者的状态都分发完,状态都与宿主的状态一致
    while (!isSynced()) {
        mNewEventOccurred = false;
        // 1.宿主的状态小于观察者状态,观察者状态进行降级
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            //状态降级
            backwardPass(lifecycleOwner);
        }
        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        // 2. 宿主的状态大于观察者状态,观察者状态进行升级
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
            // 状态升级
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}

isSynced() 判断这个接口里面注册的 Observer 是否所有观察者的状态都分发完成,都已经同步到跟宿主一致的状态。如果不是则进入状态判断:

  1. 宿主的状态小于观察者状态,观察者状态进行降级;
  2. 宿主的状态大于观察者状态,观察者状态进行升级。

如果宿主的状态小于观察者状态,这种发生在生命周期倒退的阶段,比如前台切换到后台,执行 onPause() 方法,宿主进入 STARED 状态,观察者还处于 RESUME 状态,backwardPass() 是让所有的观察者都倒退,和宿主一样的状态,并且分发相应的事件给他们,

private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    // 循环遍历所有观察者
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
        Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        // 循环对比单个观察者的状态,直到单个观察者同步到目标状态,观察者状态大于宿主状态,则将观察者状态降级处理
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            // 根据observer.mState 的状态降级,获取对应的Event事件
            Event event = Event.downFrom(observer.mState);

            pushParentState(event.getTargetState());
            // 分发相应的事件Event
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

这里的核心逻辑就是遍历所有观察者,根据当前观察者的状态,计算出它应该分发哪一种事件,由于是生命周期的倒退,这里执行的是 Event.downFrom(observer.mState),也就是生命周期的降级:

// 计算传入状态降级所对应的事件
public static Event downFrom(@NonNull State state) {
    switch (state) {
        // 如果当前的状态是 CREATED,发生生命周期倒退就是执行了ON_DESTROY,返回ON_DESTROY事件
        case CREATED:
            return ON_DESTROY;
        case STARTED:
            return ON_STOP;
        case RESUMED:
            return ON_PAUSE;
        default:
            return null;
    }
}

如果观察者是 RESUME 状态,发生生命周期倒退,就会返回一个 ON_PAUSE 事件,如果是 STARTED 状态发生生命周期的倒退也就是返回 ON_STOP 事件。

然后根据返回的事件,调用 observer.dispatchEvent() 分发给它,根据上面的分析,还会当前的事件推导出目标的状态,然后赋值给 mState。

static class ObserverWithState {
    void dispatchEvent(LifecycleOwner owner, Event event) {
        //根据Event获取目标状态
        State newState = event.getTargetState();
        // 获取最小状态
        mState = min(mState, newState);
        // 状态改变回调
        mLifecycleObserver.onStateChanged(owner, event);
        // 更新当前状态
        mState = newState;
    }
}

backwardPass() 执行完之后,观察者的状态就会降级到和宿主一样的状态,直到集合里面的所有观察者的状态和宿主的一样为止。

private void sync() {
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    //所有观察者的状态都分发完,状态都与宿主的状态一致
    while (!isSynced()) {
        // ······
        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        // 2. 宿主的状态和Observe状态比较,宿主的状态大于观察者状态,观察者状态进行升级
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
            // 状态升级
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}

同理,进入 sync() 的第二个判断条件,把当前宿主的状态和每个观察者的状态进行比较,如果大于0,生命周期前进(比如后台切换到前台),从 STARTES 状态切换到 RESUME 状态, forwardPass(lifecycleOwner) 逻辑与 backwardPass() 相似,只不过这是状态前进的过程,会调用 Event.upForm(observer.mState),根据当前观察者的状态在生命周期前进的时候计算出它应该分发哪一个事件。

private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    // 循环遍历所有观察者
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {
        Map.Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        // 观察者状小于于宿主状态,则将观察者状态升级处理
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            pushParentState(observer.mState);
            // 根据mState状态升级,获取对应的分发事件Event
            final Event event = Event.upFrom(observer.mState);
            // 分发完后就和宿主达到一致的状态
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

observer.dispatchEvent() 分发完就会与宿主达到一致的状态,直到 Observer 集合当中所有观察者与宿主的状态保持一致,并且退出这个循环。

到这里,宿主的生命周期和宿主状态的关系,每个生命周期变化的时候,都会分发相应的事件,并且根据这个事件推导出宿主的状态,遍历所有的观察者,让他们的状态也随之升级,或者降级,并且把本次事件分发给观察者。

7.如何区分LifecycleObserver的类型

那么这个事件它在分发的时候,是如何区分的 LifecycleObserver 还是 FullLifecycleObserver,亦或者是 LifecycleEventObserver 这三种类类型的?在 addObserver() 里面,每次注册一个 Observer 都会把它包装成一个 ObserverWithState

static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;
    //把传递进来的observer转换成LifecycleEventObserver
    ObserverWithState(LifecycleObserver observer, State initialState) {
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }

    void dispatchEvent(LifecycleOwner owner, Event event) {
        State newState = getStateAfter(event);
        mState = min(mState, newState);
        // 分发事件
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

它把传递进来的 observer 转换成 LifecycleEventObserver,分发事件的时候调用了 mLifecycleObserver.onStateChanged() 方法,但是我们在使用的时候明明是 LifecycleObserver 或者 FullLifecycleObserver,主要是原理在 Lifecycling.lifecycleEventObserver(observer) 里面,本质上是一个工具类,把传递进来的 observer 转化成 LifecycleEventObserver,主要是通过适配器来转化的。

static LifecycleEventObserver lifecycleEventObserver(Object object) {
    // 是否为LifecycleEventObserver类型
    boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
    // 是否为FullLifecycleObserver类型
    boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
    // 1.这种情况发生在自定义Observer,上面两种都实现了
    if (isLifecycleEventObserver && isFullLifecycleObserver) {
        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
                (LifecycleEventObserver) object);
    }
    // 2. FullLifecycleObserver 将object当做FullLifecycleObserver传递
    if (isFullLifecycleObserver) {
        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
    }
    // 3. LifecycleEventObserver 直接返回object本身
    if (isLifecycleEventObserver) {
        return (LifecycleEventObserver) object;
    }
    //······
}
  1. 判断 observer 是否为 LifecycleEventObserver && FullLifecycleObserver,如果条件都成立(一般发生在自定义的 Observer,即实现了两个接口),返回了一个FullLifecycleObserverAdapter,它实现了 LifecycleEventObserver 接口,复写了onStateChanged()方法,判断 Event 的类型,从而回调传递进来的 FullLifecycleObserver 相应的方法,如果还实现了 mLifecycleEventObserver 接口,则最后还会回调mLifecycleEventObserver.onStateChanged()方法。
// 实现LifecycleEventObserver接口
class FullLifecycleObserverAdapter implements LifecycleEventObserver {
    // mFullLifecycleObserver回调生命周期方法
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        switch (event) {
            case ON_CREATE:
                mFullLifecycleObserver.onCreate(source);
                break;
            case ON_START:
                mFullLifecycleObserver.onStart(source);
                break;
            case ON_RESUME:
                mFullLifecycleObserver.onResume(source);
                break;
            case ON_PAUSE:
                mFullLifecycleObserver.onPause(source);
                break;
            case ON_STOP:
                mFullLifecycleObserver.onStop(source);
                break;
            case ON_DESTROY:
                mFullLifecycleObserver.onDestroy(source);
                break;
        }
        // 回调mLifecycleEventObserver的onStateChanged()方法
        if (mLifecycleEventObserver != null) {
            mLifecycleEventObserver.onStateChanged(source, event);
        }
    }
}
  1. 如果仅仅是实现了 FullLifecycleObserver,同样是返回了一个FullLifecycleObserverAdapter,但是 lifecycleEventObserver 为 null,说明不再回调 onStateChanged(source, event) 方法,实际上通过 FullLifecycleObserverAdapter 包装实现转化过程,将 LifecycleObserver 转化为 LifecycleEventObserver

  2. 如果是直接实现了 LifecycleEventObserver 的则直接返回,那么在生命周期事件分发的时候, Observer 就能直接分发到 onStateChanged() 这个方法里面。

static LifecycleEventObserver lifecycleEventObserver(Object object) {
    ·····
    final Class<?> klass = object.getClass();
    // 获取Observer构造器类型,是否添加了注解编译器
    int type = getObserverConstructorType(klass);
    // 提供了两种策略
    if (type == GENERATED_CALLBACK) {
        //提供了两种策略
        List<Constructor<? extends GeneratedAdapter>> constructors =
                sClassToAdapters.get(klass);
        if (constructors.size() == 1) {
            GeneratedAdapter generatedAdapter = createGeneratedAdapter(
                    constructors.get(0), object);
            return new SingleGeneratedAdapterObserver(generatedAdapter);
        }
        GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
        for (int i = 0; i < constructors.size(); i++) {
            adapters[i] = createGeneratedAdapter(constructors.get(i), object);
        }
        // 返回CompositeGeneratedAdaptersObserver
        return new CompositeGeneratedAdaptersObserver(adapters);
    }
    // 返回ReflectiveGenericLifecycleObserver,内部实现依赖反射
    return new ReflectiveGenericLifecycleObserver(object);
}

上面的代码则是判断 LifecycleOberver,我们知道它只是一个空实现,但是为什么还要定义这个接口呢?这里仅仅是起到一个约束和规范的作用,方便在运行的时候判断 Observer 是那种类型。

public interface LifecycleObserver {

}

如果 Observer 是实现了 LifecycleOberver 这个接口的,它在运行的时候,分发事件的时候它提供了两种策略:

  1. 第一种是把 Observer 包装成一个 ReflectiveGenericLifecycleObserver,同样是实现了LifecycleEventObserver,在 onStateChanged() 调用了 invokeCallbacks() 方法通过反射的形式来调用自定义的 Observer 中相关方法。
// LifecycleObserver内部实现依赖反射
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) {
        //通过反射的形式来调用自定义的Observer中相关方法
        mInfo.invokeCallbacks(source, event, mWrapped);
    }
}
  1. 第二种如果在 gradle 文件中添加了 lifecycle_compiler 依赖,它实际上是编译器的意思,里面包含了一个注解处理器,在编译阶段就会为 Observers 生成相应适配的类。

比如上面 Lifecycle 实现方式的第一种:

public class MyLifecycleObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart(@NotNull LifecycleOwner owner) {

    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(@NotNull LifecycleOwner owner) {

    }
}

编译时会在 build.generated.source.kapt.debug 文件下自动生成MyLifecycleObserver_LifecycleAdapter.java 文件,在它的实现里面,就是根据事件的类型,回调到 MyLifecycleObserveronStart()onStop() 方法,这里为什么能直接回调呢?因为它在编译阶段生成的这个类,就能扫描到 MyLifecycleObserver 中的方法上标记的注解OnLifecycleEvent,然后拿到方法的名称,以及它的参数,生成下面的源码,就不用使用反射调用 MyLifecycleObserver 类中的方法了。

但是如何判断有没有引入 lifecycle-compiler 这个编译器的,通过 int type = getObserverConstructorType(klass) 判断构造器类型,跟踪来到 generatedConstructor() 中:

// 传入一个Class,实际上是就是上面定义的MyLifecycleObserver
private static Constructor<? extends GeneratedAdapter> generatedConstructor(Class<?> klass) {
    try {
        //获取包名
        Package aPackage = klass.getPackage();
        //获取类名
        String name = klass.getCanonicalName();
        final String fullPackage = aPackage != null ? aPackage.getName() : "";
        // 获取adapterName拼接后的类名
        final String adapterName = getAdapterName(fullPackage.isEmpty() ? name :
                name.substring(fullPackage.length() + 1));

        final Class<? extends GeneratedAdapter> aClass =
                (Class<? extends GeneratedAdapter>) Class.forName(
                        fullPackage.isEmpty() ? adapterName : fullPackage + "." + adapterName);
        Constructor<? extends GeneratedAdapter> constructor =
                aClass.getDeclaredConstructor(klass);//反射加载这个类,
        if (!constructor.isAccessible()) {//如果没有异常,说明类存在
            constructor.setAccessible(true);
        }
        return constructor;
    } catch (ClassNotFoundException e) {
        return null;
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
    }
}

adapterName 的类名拼接,实际上是 MyLifecycleObserver 拼接上 _LifecycleAdapter,如下:

public static String getAdapterName(String className) {
    return className.replace(".", "_") + "_LifecycleAdapter";
}

如果类存在了,说明引入了 lifecycle-compiler 这个编译器,如果抛出异常就说明没有引入这个编译器。

这样它就能够区分,对于是直接实现 LifecycleObserver 的情况,是返回 CompositeGeneratedAdaptersObserver 还是返回 ReflectiveGenericLifecycleObserver,从而采用不同的策略来回调方法。

四、总结

Lifecycle 原理时序图如下:

  1. 监听过程就是 Activity/Fragment 继承 LifecycleOwner,并在子类 CommponentActivity 中创建 Lifecycle 的子类 LifecycleRegistry。复写 getLifecycle() 的方法中将子类 LifecycleRegistry 返回。

  2. 在 onCreate() 中注入 ReportFragment,在生命周期回调后,通过 getLifecycle() 的方法得到 LifecycleRegistry 对象中的 handleLifecycleEvent(event) 方法给每个观察者派发生命周期事件。

  3. addObserver() 中先初始化状态,然后计算出它应该到达的状态(目标状态),while()循环会让当前的观察者的状态从init状态前进到目标状态,再根据状态获取相应的事件,Observe 调用 dispatchEvent() 分发事件。

  4. 宿主每个生命周期方法里面执行 handleLifecycleEvent(event),event.getTargetState() 根据当前的事件推导出每个观察者目标的生命周期状态,进行升级或者降级处理。然后遍历所有观察者,根据当前观察者的状态,计算出它对应的事件,分别进行 observer.dispatchEvent() 分发事件。

关于 Lifecycle 面试常问几个问题:

  1. Activity 里面是如何实现 Lifecycle 事件的分发的?

答:是通过添加透明 ReportFragment.

  1. 在 onResume 方法里面注册 Observer,是否能接受到完整的分发事件?

答:能。

Lifecycle 几乎是 Jetpack 组件的核心,所有具有生命周期感知能力的组件都会用到 Lifecycle,包括 ViewModel和 Livedata。Lifecycle 实现了执行的逻辑和活动的分离,代码解耦并且增加了代码的额可读性。Lifecycle 在活动结束时自动移除监听,避免了生命周期的问题。

总的来说,观察宿主生命周期有三种写法,推荐第二种和第三种,第一种需要使用注解标记,要么是反射,要么是要添加注解处理器,生成适配的类。

一个大型的 Android 项目架构最佳实践,基于Jetpack组件 + MVVM架构模式,加入 组件化模块化协程Flow短视频


为了帮助大家更好的熟知Jetpack Compose 全家桶这一套体系的知识点,这里记录比较全比较细致的《Jetpack 全家桶》(内含Compose) 学习笔记!!! 对Jetpose Compose这块感兴趣的小伙伴可以参考学习下……

Jetpack 全家桶(Compose)

Jetpack 部分

  1. Jetpack之Lifecycle
  2. Jetpack之ViewModel
  3. Jetpack之DataBinding
  4. Jetpack之Navigation
  5. Jetpack之LiveData

Compose 部分
1.Jetpack Compose入门详解
2.Compose学习笔记
3.Compose 动画使用详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/687666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【并发编程】多线程安全问题,如何避免死锁

文章目录 概念进程线程对比 代码使用进程线程 线程创建方式线程的生命周期和状态停止线程方法介绍sleep() / wait()为什么 wait() 不被定义在 Thread 中&#xff1f;sleep() 定义在 Thread 中&#xff1f;run()/start() 为什么使用多线程&#xff1f;线程安全问题线程死锁如何避…

可孚医疗:「最懂互联网」的医疗器械企业是如何炼成的?

如果说钉钉在过去的标签是软件&#xff0c;是低代码。那么在医疗这个赛道里&#xff0c;这些标签已经不足以成为钉钉价值的侧写&#xff0c;除了固有标签之外&#xff0c;在可孚医疗的场景里&#xff0c;钉钉可以连接&#xff0c;可以成为智能BI&#xff0c;也更可以做到内外部…

(旧版) 家居购项目 1.分页导航 2.购物车 3.订单生成 4.权限验证 5.事务管理 6.上传图片

文章目录 &#x1f400;Java后端经典三层架构&#x1f407;MVC模型&#x1f407;开发环境搭建&#x1f407;会员注册&#x1f333;前端验证用户注册信息&#x1f333;思路分析&#x1f349;创建表&#x1f349;创建实体类&#x1f349;DAO&#x1f34c;MemberDAOImpl &#x1f…

kali磁盘空间不足,软连接解决apt下载问题

知识点&#xff1a; ①在Linux系统下(其他操作系统也有类似的规定)&#xff0c;磁盘的分区大致可以分为三类&#xff0c;分别为主分区、扩展分区和逻辑分区等等。 ②主分区可以有1-4个&#xff0c;扩展分区可以有0-1个&#xff0c;逻辑分区编号从5开始。 ③主分区可以直接进行格…

数据库信息速递 DataStax与谷歌合作将向NoSQL AstraDB引入向量搜索技术

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

机器学习5:基于线性回归理解减少“损失”的方法

在上节《机器学习4&#xff1a;基本术语》中&#xff0c;笔者介绍了“损失&#xff08;Loss&#xff09;”的定义&#xff0c;在训练模型时&#xff0c;减少损失&#xff08;Reducing Loss&#xff09;是极为关键的&#xff0c;只有“损失”足够小的机器学习系统才有实用价值。…

【数据库】mysql主从复制与读写分离

文章目录 一、读写分离1. 什么是读写分离2. 为什么要读写分离3. 什么时候要读写分离4. 主从复制与读写分离5. Mysql 主从复制原理&#xff08;主从复制的类型&#xff09;6. Mysql 主从复制的工作过程7. Mysql 读写分离原理 二、主从复制的配置操作1. 环境配置2. 搭建 MySQL主从…

从第一性原理揭秘爱因斯坦相对论

摘要&#xff1a; 本文首先将探讨狭义相对论的基本原理及其起源。接着&#xff0c;我们将深入分析狭义相对论的世界观给我们的认知带来了哪些本质的改变。最后&#xff0c;我们将探讨狭义相对论为何无法解决引力的矛盾性问题&#xff0c;以及广义相对论是如何有效解决此类问题的…

最大匹配问题---男女匹配问题(算法)

扯淡&#xff1a; 今天期末复习的时候发现一个算法很有意思&#xff0c;就是男女最大分配对象问题&#xff0c;几对男女最多能凑够几对对象。 根据社会主义核心价值观&#xff0c;我们最好整一夫一妻制&#xff0c;分配一人一对象&#xff0c;我辈义不容辞。 题目分析&#…

需求分析六步法

需求收集可能看起来不言自明&#xff0c;但它很少得到应有的充分关注。就像运动前伸展或睡前刷牙一样&#xff0c;这是一项经常被忽视的简单任务。 但是&#xff0c;忽视这些看似简单的事情的后果可能会导致伤害、蛀牙&#xff0c;或者在项目管理的情况下&#xff0c;导致项目…

GeoServer发布图层遇到的几个雷点及解决方案

目录 前言 一、图层编码导致图层预览无服务的异常问题 1、问题描述 2、问题分析 3、问题解决 二、图层空间参考投影设置的问题 1、问题描述 2、问题分析 3、问题解决 三、Qgis导出的SLD在GeoServer中发布预览报错的问题 1、问题描述 2、问题分析 3、问题解决 四、GeoS…

java 临床症状识别系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 JSP 临床症状识别系统 是一套完善的系统源码&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S 模式开发。 研究的基本内容是基于Web的临床症状识别…

一文详解如何用GPU来运行Python代码/基于Python自制一个文件解压缩小工具

前几天捣鼓了一下Ubuntu&#xff0c;正是想用一下我旧电脑上的N卡&#xff0c;可以用GPU来跑代码&#xff0c;体验一下多核的快乐&#xff0c;感兴趣的小伙伴快跟随小编一起了解一下吧 简介 前几天捣鼓了一下Ubuntu&#xff0c;正是想用一下我旧电脑上的N卡&#xff0c;可以用…

Nova代码解析

1. 引言 前序博客有&#xff1a; Nova: Recursive Zero-Knowledge Arguments from Folding Schemes学习笔记基于cycle of curves的Nova证明系统&#xff08;1&#xff09;基于cycle of curves的Nova证明系统&#xff08;2&#xff09; 微软团队2021年论文 《Nova: Recursive…

警惕2本期刊被剔除!2023年6月EI目录已更新!(附全目录下载)

2023年6月EI期刊目录更新 爱思唯尔官网近日更新了EI期刊目录&#xff0c;此次更新是2023年6月1日&#xff0c;与上次更新&#xff08;2023年2月&#xff09;相比&#xff0c;有3本期刊名称在Serials&#xff08;连续出版&#xff09;列表中搜索不到&#xff0c;其中&#xff0…

【前端|HTML系列第2篇】HTML零基础入门之标签元素

大家好&#xff0c;欢迎来到前端入门系列的第二篇博客。在这个系列中&#xff0c;我们将一起学习前端开发的基础知识&#xff0c;从零开始构建网页和Web应用程序。本篇博客将为大家介绍HTML&#xff08;超文本标记语言&#xff09;常用标签元素&#xff0c;帮助零基础小白快速入…

Upload靶场通关笔记(更新中)

文章目录 一、Pass-011.抓包上传2.获取上传路径3.工具验证 二、Pass-02三、Pass-031.使用httpd.conf自定义后缀2.提取上传文件名3.工具测试4.注意点四、Pass-041.上传.htaccess2.上传图片3.工具测试 五、Pass-05六、Pass-061.空格.号绕过2.工具测试 七、Pass-07八、Pass-081.特…

电气工程师日常工作常遇到的41种接线方法(一)

01 电动机接线 一般常用三相交流电动机接线架上都引出6个接线柱&#xff0c;当电动机铭牌上标为Y形接法时&#xff0c;D6、D4、D5相连接&#xff0c;D1-D3接电源&#xff1b;为△形接法时&#xff0c;D6与D1连接&#xff0c;D4与D2连接&#xff0c;D5与D3连接&#xff0c;然后…

报表软件测评|如何选择一款简单易用的报表开发工具

报表业务的稳定性天生较差&#xff0c;随着业务的推进&#xff0c;会不断产生新的查询统计需求&#xff0c;报表也必须相应地不断增加、修改。这导致报表的数量似乎没有止境。通常情况下&#xff0c;企业信息系统的主要功能模块在上线后相对稳定&#xff0c;不再变化&#xff0…

文心一言 VS 讯飞星火 VS chatgpt (48)-- 算法导论6.1 6题

值为<23&#xff0c;17&#xff0c;14&#xff0c;6&#xff0c;13&#xff0c;10&#xff0c;1&#xff0c;5&#xff0c;7&#xff0c;12>的数组是一个最大堆吗? 文心一言&#xff1a; 是的&#xff0c;这个数组是一个最大堆。 最大堆是一种特殊的二叉树&#xff0…