主頁 >  其他 > Jetpack框架探究01:Lifecycle組件的使用與原始碼分析

Jetpack框架探究01:Lifecycle組件的使用與原始碼分析

2021-01-12 11:00:44 其他

總目錄

Jetpack框架探究01:Lifecycle組件的使用與原始碼分析
Jetpack框架探究02:LiveData組件的使用與原始碼分析
Jetpack框架探究03:ViewModel組件的使用與原始碼分析
Jetpack框架探究04:Room組件的使用與原始碼分析
Jetpack框架探究05:WorkerManager組件的使用與原始碼分析

1. Lifecycle簡介

?Lifecycle是Android Jetpack框架提供的能夠感知組件(宿主)生命周期變化的組件,它能持有宿主(如Activity或Fragment)生命周期狀態的資訊,并且允許其他觀察者注冊監聽宿主的生命周期狀態變化,這就使得我們不用主動去獲取宿主的狀態,有利于降低代碼耦合度并更容易維護,Lifecycle是JetPack組件庫的核心基礎,很多其他的Jetpack組件,比如LiveDataViewMoedel等,都是基于它實作的,

1.1 Lifecycle基本使用

?Lifecycle的使用非常簡單,主要分為以下三步:

(1)添加依賴,直接匯入androidx庫即可;

android {
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'

    // 如果需要支持 Java8 的組件,需要引入 lifecycle:common-java8
    // DefaultLifecycleObserver需要Java8
    implementation "android.arch.lifecycle:common-java8:1.1.1"
}

注:如果觀察者使用繼承DefaultLifecycleObserver方式,則需要Java8支持,

(2)實作一個觀察者;

?創建一個觀察者Observer主要有三種實作方式,即LifecycleObserverLifecycleEventObserverDefaultLifecycleObserver,其中,后兩者均繼承于LifecycleObserver,它是一個空的介面,如果直接繼承這個介面,將通過注解的方式實作監聽回呼,但相比注解方式,官方更推薦使用DefaultLifecycleObserver,該介面也允許我們選擇性的實作對應的回呼方法,注意,它需要Java8支持,

class MyLifecycleObserver: DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) {
        super.onStart(owner)
        Log.i("LifecycleObserver", "I'm observer, activity now in--->onStart")
    }

    override fun onStop(owner: LifecycleOwner) {
        super.onStop(owner)
        Log.i("LifecycleObserver", "I'm observer, activity now in--->onStop")
    }
}

(3)注冊觀察者;

?為了實作對宿主生命周期狀態的監聽,我們需要將一個觀察者物件注冊到宿主中,這個程序主要是通過獲取宿主的Lifecycle物件,并呼叫它的addObserver()方法實作的,該方法的具體實作在LifecycleRegister中,這個類是Lifecycle的唯一實作類,以監聽Activity為例:

class StudyLifecycleActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        addLifecycleObserver()
    }

    private fun addLifecycleObserver() {
        lifecycle.addObserver(MyLifecycleObserver())
    }
}

?至此,當Activity的生命周期變化時,與其對應的觀察者方法將被回呼,

1.2 Lifecycle實戰案例

?為了加深對Lifecycle感知組件生命周期變化的理解,這里舉一個在開發中經常遇到的例子,即判斷APP是否顯示在前臺,本例需要結合Application的registerActivityLifecycleCallbacks()方法實作,該方法的作用是當Activity的生命周期發生變化時,其對應的方法就會被回呼,基于此,我們創建一個自定義組件,使其繼承于LifecycleOwner,并擁有Lifecycle.Event.ON_STARTLifecycle.Event.ON_STOP生命周期事件,分別表示APP的狀態處于前臺和后臺,該組件具體原始碼如下:

/**
 * author: jiangdg
 * date: 2021/1/8 2:35 PM
 * description: 自定義宿主,擁有Start和Stop生命周期事件
 */
object AppStatusOwner:  LifecycleOwner {

    private val mLifecycleRegistry = LifecycleRegistry(this)

    override fun getLifecycle(): Lifecycle = mLifecycleRegistry

    fun init(application: Application) {
        application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
            private var activityFrontCount = 0

            override fun onActivityStarted(activity: Activity) {
                // 第一個activity置于前臺時
                // 向外部發送Lifecycle.Event.ON_START事件,表示APP當前處于前臺
                if (activityFrontCount == 0) {
                    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
                }

                activityFrontCount++
            }

            override fun onActivityStopped(activity: Activity) {
                activityFrontCount--

                // 當前沒有Activity置于前臺時
                // 向外部發送Lifecycle.Event.ON_STOP事件,表示APP當前處于后臺
                if (activityFrontCount == 0) {
                    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
                }
            }

            override fun onActivityPaused(activity: Activity) {
            }

            override fun onActivityDestroyed(activity: Activity) {
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
            }

            override fun onActivityResumed(activity: Activity) {
            }
        })
    }
}

?然后,我們通過繼承DefaultLifecycleObserver創建一個觀察者,并實作onStartonStop方法,當onStart()方法被回呼時表明APP當前置于前臺,當onStop()方法被回呼時表明APP當前置于后臺,代碼如下:

/**
 * author: jiangdg
 * date: 2021/1/8 3:08 PM
 * description: APP前后臺狀態觀察者
 */
class AppStatusObserver: DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) {
        super.onStart(owner)

        Log.i("AppStatusObserver", "APP置于前臺")

        // 發送APP置于前臺廣播
    }

    override fun onStop(owner: LifecycleOwner) {
        super.onStop(owner)

        Log.i("AppStatusObserver", "APP置于后臺")

        // 發送APP置于前臺廣播
    }
}

?最后,在Application類中進行初始化操作,代碼如下:

class JetpackApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        
        // 啟動監聽所有Activity的狀態變化
        AppStatusOwner.init(this)
        // 注冊觀察者到宿主
        AppStatusOwner.lifecycle.addObserver(AppStatusObserver())
    }
}

2. Lifecycle實作原理

2.1 Lifecycle框架模型

?Lifecycle框架類圖如下:

在這里插入圖片描述

?從Lifecycle框架模型可知,該框架感知一個組件的生命周期狀態變化原理為:首先,讓一個組件(如Activity或Fragment)繼承LifecycleOwner介面,用以表明自己是一個擁有生命周期變化的組件(宿主),同時重寫lifecycleOwner介面的getLifecycle()方法,該方法會回傳一個Lifecycle物件;然后,通過繼承LifecycleObserver介面實作一個觀察者,并呼叫Lifecycle物件的addObserver()方法進行注冊監聽,當宿主生命周期發生變化時宿主內部就會通過Lifecycle的唯一實作類LifecycleRegister將生命周期事件分發給所有觀察者;最后,觀察者與生命周期事件對應的方法將會被自動回呼, 類或介面具體說明如下:

  • LifecycleOwner

?LifecycleOwner是一個介面,它用于表明一個類是能夠提供生命周期事件的宿主,Activity和Fragment均實作了LifecycleOwner,并重寫了LifecycleOwner的getLifecycle()方法,該方法回傳一個Lifecycle物件,當然,任何類均可以實作LifecycleOwner,表示該類是一個能夠提供生命周期事件的宿主,LifecycleOwner原始碼如下:

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}
  • Lifecycle

?Lifecycle是一個抽象類,用于存盤有關組件(或稱宿主,比如Activity/Fragment)的生命周期狀態的資訊,并允許其他物件觀察此狀態,Lifecycle使用兩種主要列舉跟蹤其關聯宿主的生命周期狀態,即事件狀態,其中,事件為宿主的生命周期事件,而狀態為Lifecycle物件跟蹤的宿主的當前狀態,不同的事件可能對應相同的狀態,Lifecycle原始碼如下:

public abstract class Lifecycle {

    // 注冊生命周期事件觀察者
    // 所有的觀察者為LifecycleObserver或其子類
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);
    
    // 移除生命周期事件觀察者
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);
    
    // 獲取Lifecycle當前的狀態
    @MainThread
    @NonNull
    public abstract State getCurrentState();
    
    // 宿主生命周期
    // 比如ON_CREATE即為生命周期onCreate
    public enum Event {
        ON_CREATE,
        ON_START,
        ON_RESUME,
        ON_PAUSE,
        ON_STOP,
        ON_DESTROY,
        ON_ANY
    }

    // 宿主的狀態型別
    // 比如CREATED狀態對應于宿主生命周期為onCreate/onStop
    @SuppressWarnings("WeakerAccess")
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
}
  • LifecycleRegister

?LifecycleRegister是Lifecycle的唯一實作類,主要用來負責注冊Observer(觀察者),以及分發宿主狀態事件給這些觀察者,LifecycleRegister維護著一個Map集合,該集合存盤了已注冊的觀察者以及它們當前的狀態,同時維護一個State物件表示當前宿主的狀態,從LifecycleRegister的構造方法可以看出,宿主的初始狀態為INITIALIZED,LifecycleRegister原始碼如下:

public class LifecycleRegistry extends Lifecycle {

    // Observer串列
    // ObserverWithState包裝了要注冊的Observer及其當前狀態
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
        new FastSafeIterableMap<>();
    
    // 宿主當前狀態
    private State mState
    
    public LifecycleRegistry(@NonNull LifecycleOwner provider) {
        mLifecycleOwner = new WeakReference<>(provider);
        // 初始狀態INITIALIZED
        mState = INITIALIZED;
    }
    
    // 注冊Observer
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        ...
    }
    
    // 移除Observer
    @Override
    public void removeObserver(@NonNull LifecycleObserver observer) {
        mObserverMap.remove(observer);
    }
    
    ...
}
  • LifecycleObserver

?LifecycleObserver是一個介面,用于宣告一個類為Lifecycle的觀察者,LifecycleObserver是一個空的介面,通常我們使用注解或它的實作類,比如LifecycleEventObserverDefaultLifecycleObserver等,來監聽宿主lifecycle的變化,原始碼如下:

// LifecycleObserver類
public interface LifecycleObserver {
}

// LifecycleEventObserver類
public interface LifecycleEventObserver extends LifecycleObserver {
    /**
     * 當宿主生命周期事件變化時,該方法被回呼
     *
     * @param 宿主,即被觀察的物件
     * @param event 生命周期事件
     */
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

// DefaultLifecycleObserver類
// 當使用Java 8時,推薦使用它
public interface DefaultLifecycleObserver extends FullLifecycleObserver {

   /**
     * 當宿主的生命周期事件為ON_CREATE時
     * 該方法被回呼
     *
     * @param owner 宿主,即被觀察的物件
     */
    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {
    }

    ...
}

2.2 Lifecycle狀態模型

?Lifecycle狀態模型描述了宿主生命周期宿主狀態之間的關系,簡單來說,就是指當宿主的生命周期變化時,它處于哪一種狀態,總共有五種狀態:INITIALIZEDCREATEDSTARTEDRESUMEDDESTROYED,LifecycleRegistry在分發事件時依賴這兩種之間的關系,宿主生命周期與宿主狀態模型圖如下:

在這里插入圖片描述

2.3 原始碼分析

2.3.1 Fragment實作Lifecycle原理

// androidx.fragment.app.Fragment
public class Fragment implements LifecycleOwner,.. 
{
    LifecycleRegistry mLifecycleRegistry;
    
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
    
    private void initLifecycle() {
        mLifecycleRegistry = new LifecycleRegistry(this);
        mSavedStateRegistryController = SavedStateRegistryController.create(this);
    }
    
    void performCreate(Bundle savedInstanceState) {
        // 設定Fragment當前狀態為CREATED
        mState = CREATED;
        onCreate(savedInstanceState);
        ...
        // 分發Fragment的生命周期onCreate
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }
    
    void performActivityCreated(Bundle savedInstanceState) {
        // 設定Fragment當前狀為ACTIVITY_CREATED
        // 沒有分發生命周期
        mState = ACTIVITY_CREATED;
        ...
        onActivityCreated(savedInstanceState);
    }
    
    void performStart() {
        mState = STARTED;
        onStart();
        ...
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }
    
    void performResume() {
        mState = RESUMED;
        onResume();
        ...
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }
    
    void performPause() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
        mState = STARTED;
        ...
        onPause();
    }
    
    void performStop() {
        mState = ACTIVITY_CREATED;
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
        ...
        onStop();
    }
    
     void performDestroyView() {
        // 設定Fragment當前狀為CREATED
        // 沒有分發生命周期
        mState = CREATED;
        ...
        onDestroyView();
    }
    
    void performDestroy() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        mState = INITIALIZING;
        ...
        onDestroy();
    }
}

?從Fragment原始碼可知,它通過繼承于LifecycleOwner介面,表明自己是一個擁有生命周期變化的組件,并實作該介面的getLifecycle()方法,該方法回傳一個Lifecycle物件,實際上回傳的是Lifecycle的唯一子類LifecycleRegistry,當Fragment的生命周期狀態變化時,Fragment會更新自己的狀態State,并通過LifecycleRegistry向外界(所有觀察者)分發對應的生命周期事件,

2.3.2 Activity實作Lifecycler原理

// AppcompatActivity父類
public class ComponentActivity implements LifecycleOwner...{
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSavedStateRegistryController.performRestore(savedInstanceState);
        // 將ReportFragment添加到Activity中
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }
    
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
    
    ...
}

// ReportFragment
public class ReportFragment extends Fragment {

    public static void injectIfNeededIn(Activity activity) {
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            manager.executePendingTransactions();
        }
    }
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

    @Override
    public void onStart() {
        super.onStart();
        dispatchStart(mProcessListener);
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatchResume(mProcessListener);
        dispatch(Lifecycle.Event.ON_RESUME);
    }
    
    ...
    
    private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        // 呼叫LifecycleRegistry的handleLifecycleEvent方法
        // 向外分發生命周期變化事件
        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);
            }
        }
    }
}

?從上述原始碼可知,Activity實作Lifecycle需要借助于ReportFragment往Activity上添加一個 fragment 用以報告生命周期的變化,目的是為了兼顧不是繼承自 AppCompactActivity的場景,同時也支持我們自定義LifecycleOwner的場景,假如我們自定義一個繼承于android.app.Activity的Activity需要實作Lifecycle,就需要借助于ReportFragment來實作,示例代碼如下:

class StudyLifecycleActivity2: Activity(), LifecycleOwner {

    private val mLifecycleRegistry = LifecycleRegistry(this)
    
    // 回傳一個LifecycleRegistry物件
    override fun getLifecycle(): Lifecycle = mLifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 添加ReportFragment到Activity
        ReportFragment.injectIfNeededIn(this)
        
        // 注冊觀察者
        addLifecycleObserver()
    }

    private fun addLifecycleObserver() {
        lifecycle.addObserver(MyLifecycleObserver())
    }
}

2.3.3 事件分發程序

?Lifecycle事件分發時序圖:

在這里插入圖片描述

?從Fragment和Activity實作Lifecycle原理可知,當宿主的生命周期發生變化時,就會通過呼叫LifecycleRegistryhandleLifecycleEvent()方法向外分發生命周期變化事件,該方法原始碼如下:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    // (1)獲取宿主當前生命周期事件對應的狀態
    State next = getStateAfter(event);
    // (2)進入事件分發流程
    moveToState(next);
}

?事件分發具體程序如下:

?(1)呼叫getStateAfter()方法獲取當前生命周期事件對應的狀態;

static State getStateAfter(Event event) {
    switch (event) {
        case ON_CREATE:
        case ON_STOP:
            return CREATED;
        case ON_START:
        case ON_PAUSE:
            return STARTED;
        case ON_RESUME:
            return RESUMED;
        case ON_DESTROY:
            return DESTROYED;
        case ON_ANY:
            break;
    }
    throw new IllegalArgumentException("Unexpected event value " + event);
}

?(2)呼叫moveToState更新宿主的狀態mState,然后呼叫sync方法通過比對宿主當前的狀態和觀察者之前保存的狀態,完成觀察者狀態同步和事件分發,在sync方法中,首先會呼叫isSynced()方法判斷是否需要同步觀察者的狀態;然后再判斷當前事件的狀態如果小于mObserverMap集合中最先添加的觀察者狀態,說明宿主的狀態發生了回退,比如之前是RESUMED狀態,執行了onPause()則回退到STARTED狀態,此時就會呼叫backwardPass()方法把集合中的每一個觀察者分發一個ON_PAUSE事件,并同步該觀察者的狀態,同理,如果當前事件宿主狀態大于mObserverMap集合最近添加的觀察者狀態,說明宿主的狀態發生了前進,此時就好呼叫forwardPass()分發事件,并同步該觀察者狀態,相關原始碼如下:

private void sync() {
    ...
    while (!isSynced()) {
        mNewEventOccurred = false;
        // 宿主狀態回退
        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;
}

?在backwardPass()forwardPass()方法中,它們均會去遍歷mObserverMap集合,獲取與觀察者關聯的ObserverWithState物件,該物件存盤了觀察者及其狀態,然后,判斷這些Observer的狀態State是否滿足要求,如果滿足,則呼叫dispatchEvent()方法同步觀察者的狀態,同時呼叫觀察者的onStateChanged()方法完成宿主生命周期變化事件的分發,ObserverWithState原始碼如下:

static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;

    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);
        // 分發生命周期變化事件
        // 注:這里表明了無論我們使用哪種方式實作觀察者
        // Lifecycle原始碼中最終將統一轉換為LifecycleEventObserver
        // 即通過它來完成最終的事件分發,以便統一分發形式
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

2.3.4 觀察者注冊程序

?Lifecycle注冊觀察者時序圖:

在這里插入圖片描述

?從上述時序圖可知,Lifecycle的觀察者注冊是從呼叫LifecycleRegistryaddObserver()方法開始的,該方法首先會根據宿主當前的狀態為新添加的觀察者設定一個初始狀態,只要不是在onDestory方法中注冊,那么觀察者的初始狀態為INITIALIZED;然后將observer包裝成ObserverWithState,并添加到mObserverMap集合中;最后就是一個while回圈,即不斷拿觀察者的狀態與宿主當前狀態作比較以判斷是否對齊,如果沒有則向觀察者分發對應的事件,同時更新觀察者的狀態,直到兩者的狀態一致,addObserver方法原始碼如下:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    // 指定新添加觀察者的初始狀態
    // 只要不在onDestory方法中注冊,初始狀態為INITIALIZED
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // 將observer包裝成ObserverWithState,它存盤了觀察者及其狀態
    // 使用ObserverWithState的目的就是方便在分發事件時作狀態對比
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // 將ObserverWithState添加到集合
    // 如果之前已經添加,則return
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    if (previous != null) {
        return;
    }
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        return;
    }
    
    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    // 同步觀察者的狀態,舉個例子:
    //假設是在宿主的onresume犯法內注冊的該觀察者
    //第一次:分發on_Create事件,觀察者狀態INIT->CREATED 
    //第二次:分發on_Start事件,觀察者狀態CREATED->STARTED 
    //第三次:分發on_Resume事件,觀察者狀態STARTED->RESUMED
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        // 分發事件
        statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
        popParentState();
        // 再一次計算觀察的狀態是否與宿主一致
        targetState = calculateTargetState(observer);
    }

    if (!isReentrance) {
        // we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}

Github原始碼:ExampleJetpack

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/247603.html

標籤:AI

上一篇:如何用Python的標準print函式列印一個彩色的圍棋局面?

下一篇:使用 SQL 陳述句實作一個年會抽獎程式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more