如何繫結頁面生命週期(二)-基於Android Architecture Components的Lifecycle實現

宇是我發表於2018-07-28

上篇文章如何繫結頁面生命週期(一)-Glide實現介紹了Glide實現生命週期感知的原理,這裡我們再介紹基於Android Architecture Components的Lifecycle實現頁面生命週期感知。

Lifecycle是Android Architecture Components(之後簡稱AAC)的一個元件,用於將系統元件(Activity、Fragment等等)的生命週期分離到Lifecycle類,Lifecycle允許其他類作為觀察者,觀察元件生命週期的變化。

基於AAC實現元件生命週期觀察實踐

  • 控制元件實現LifecycleObserver介面,內部通過@OnLifecycleEvent註解宣告生命週期事件
public class LifecycleObserverDemo implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    void onAny(LifecycleOwner owner, Lifecycle.Event event) {
        System.out.println("onAny:" + event.name());
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate() {
        System.out.println("onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy() {
        System.out.println("onDestroy");
    }
}
複製程式碼
  • 在LifecycleRegistryOwner,比如在實現了LifecycleRegistryOwner介面的Activity中。定義LifecycleRegistry例項,並將控制元件lifecycleRegistry例項中的監聽集合中。
public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {
	// 定義LifecycleRegistry例項
    private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 加入監聽集合
        getLifecycle().addObserver(new LifecycleObserverDemo());        
    }

    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}
複製程式碼

只需要如上兩步,當Activity頁面生命週期發生變化時,都會通知到LifecycleObserverDemo。同樣,本文以Activity為例,介紹Lifecycle感知生命週期的原理。

生命週期繫結實現原理

實現原理簡介

通過在對指定activity註冊無UI的Fragment,傳遞頁面Activity生命週期到Fragment。然後通過Fragment繫結LifecycleRegistry,當Fragment的生命週期變化時,回撥LifecycleRegistry中LifecycleObserver物件相應的生命週期回撥方法。

如何傳遞生命週期

下圖是文章Android Architecture Component -- Lifecycle 淺析中關於Lifecycle生命週期傳遞的一幅圖,我覺得很清晰地展示了生命週期的傳遞過程。下面我們跟著這幅圖,來一步步看一下生命週期是如何傳遞的。

生命週期傳遞到LifecycleObserver

  • 如何在Activity上註冊無UI的ReportFragment

    首先看下LifecycleDispatcher初始化的過程:

    • 利用 ContentProvider 的特點在應用程式初始化時,向其注入兩行程式碼:
    LifecycleDispatcher.init(getContext());
    ProcessLifecycleOwner.init(getContext());  // 監聽整個應用前後臺切換
    複製程式碼
    • 這個ContentProvider從哪裡來?檢視apk中的AndroidManifest.xml檔案,發現多了一個ContentProvider宣告:
    <provider
        android:name="android.arch.lifecycle.LifecycleRuntimeTrojanProvider"
        android:authorities="${applicationId}.lifecycle-trojan"
        android:exported="false"
        android:multiprocess="true" />
    複製程式碼

在這個LifecycleRuntimeTrojanProvider(低版本的AAC裡,這個類叫ProcessLifecycleOwnerInitializer)的初始化方法中,實現了LifecycleDispatcher的相應初始化操作。

下面再來看一下LifecycleDispatcher的init方法:

static void init(Context context) {
    if (sInitialized.getAndSet(true)) {
        return;
    }
    ((Application) context.getApplicationContext())
            .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
}
複製程式碼

在 LifecycleDispatcher#init(Context) 中,它通過 registerActivityLifecycleCallbacks 方法,向當前的 Application 註冊一個 DispatcherActivityCallback。但 Lifecycle 並沒使用 ActivityLifecycleCallbacks 來監聽並派發生命週期事件。而是通過一個無 UI 的 Fragment,在 DispatcherActivityCallback#onActivityCreated 可以看到它在 Activity#onCreate 時,為 Activity 新增一個 ReportFragment。最終由 ReportFragment 來監聽各個生命週期事件,然後傳遞給 LifecycleRegistry。

  • 無UI的Fragment與LifecycleRegistry建立聯絡

檢視ReportFragment的生命週期回撥方法:

@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);
}

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

@Override
public void onStop() {
    super.onStop();
    dispatch(Lifecycle.Event.ON_STOP);
}

@Override
public void onDestroy() {
    super.onDestroy();
    dispatch(Lifecycle.Event.ON_DESTROY);
    // just want to be sure that we won't leak reference to an activity
    mProcessListener = null;
}
複製程式碼

回撥生命週期方法時,會呼叫dispatch(Lifecycle.Event event)方法。看下dispatch(Lifecycle.Event event)方法的原始碼:

private void dispatch(Lifecycle.Event event) {
    Activity activity = getActivity();
    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);
        }
    }
}
複製程式碼

這裡會通過ReportFragment註冊的Activity的getLifecycle()方法獲取LifecycleRegistry,然後呼叫LifecycleRegistry的handleLifecycleEvent(@NonNull Lifecycle.Event event)處理傳遞的生命週期Event。

  • _LifecycleAdapter如何與LifecycleRegistry建立聯絡

    在LifecycleRegistry中,定義瞭如下的map:

    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
    複製程式碼

    當我們在頁面Activity中將觀察者加入集合時,加入的就是上面定義的mObserverMap。ObserverWithState物件建構函式初始化時,通過Lifecycling.getCallback(observer)方法返回GenericLifecycleObserver物件,實際上就是_LifecycleAdapter物件。因為_LifecycleAdapter實現了GenericLifecycleObserver。

    static GenericLifecycleObserver getCallback(Object object) {
        if (object instanceof FullLifecycleObserver) {
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object);
        }
    
        if (object instanceof GenericLifecycleObserver) {
            return (GenericLifecycleObserver) object;
        }
    
        final Class<?> klass = object.getClass();
        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);
            }
            return new CompositeGeneratedAdaptersObserver(adapters);
        }
        return new ReflectiveGenericLifecycleObserver(object);
    }
    複製程式碼

基於註解生成了_LifecycleAdapter 的class,通過反射生成_LifecycleAdapter物件

  • _LifecycleAdapter回撥生命週期方法,繼續傳遞生命週期給最終的觀察者

LifecycleRegistry和_LifecycleAdapter建立聯絡後,生命週期會通過呼叫ObserverWithState的dispatchEvent方法:

void dispatchEvent(LifecycleOwner owner, Event event) {
    State newState = getStateAfter(event);
    mState = min(mState, newState);
    mLifecycleObserver.onStateChanged(owner, event);
    mState = newState;
}
複製程式碼

最終,會呼叫mLifecycleObserver,即我們前面返回的_LifecycleAdapter的onStateChanged方法。下面看下_LifecycleAdapter的實現:

public class LifecycleObserverDemo_LifecycleAdapter implements GenericLifecycleObserver {
  final LifecycleObserverDemo mReceiver;

  LifecycleObserverDemo_LifecycleAdapter(LifecycleObserverDemo receiver) {
    this.mReceiver = receiver;
  }

  @Override
  public void onStateChanged(LifecycleOwner owner, Lifecycle.Event event) {
    mReceiver.onAny(owner,event);
    if (event == Lifecycle.Event.ON_CREATE) {
      mReceiver.onCreate();
    }
    if (event == Lifecycle.Event.ON_START) {
      mReceiver.onStart();
    }
    if (event == Lifecycle.Event.ON_PAUSE) {
      mReceiver.onPause();
    }
    if (event == Lifecycle.Event.ON_DESTROY) {
      mReceiver.onDestroy();
    }
  }

  public Object getReceiver() {
    return mReceiver;
  }
}
複製程式碼

上面的類,可以在 build 目錄下找到。這是註解處理器為我們生成了 LifecycleObserverDemo_LifecycleAdapter,不過這只是一個介面卡,用於將生命週期事件派發到 LifecycleObserverDemo 對應的方法。至此,LifecycleObserverDemo實現了對頁面Activity生命週期的感知。

核心類介紹

  • LifecycleObserver:介面,標記一個類是可觀察的,基於註解實現相應回撥方法
  • Lifecycle:抽象類,擁有android生命週期
  • LifecycleRegistry:繼承Lifecycle,可以處理多LifecycleObserver
  • LifecycleOwner:介面,持有一個android lifecycle
  • LifecycleRegistryOwner:介面,繼承LifecycleOwner,返回LifecycleRegistry
  • LifecycleDispatcher:在Application中hook,觀察activity的生命週期並分發
  • LifecycleRuntimeTrojanProvider:LifecycleDispatcher等初始化

生命週期管理框架實踐

Demo省略了註解相關步驟,需要觀察者自己去實現一個ZRLifecycleObserver介面。雖然稍有不同,但是不妨礙理解。

Demo的框架圖如下所示:

框架圖

使用的話也比較簡單,主要進行以下一些設定。

  • 觀察者實現ZRLifecycleObserver介面
public class MyView extends View implements ZRLifecycleObserver {

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context,
            @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void onCreate() {
        System.out.println("MyView onCreate");
    }

    @Override
    public void onStart() {
        System.out.println("MyView onStart");
    }

    @Override
    public void onResume() {
        System.out.println("MyView onResume");
    }

    @Override
    public void onPause() {
        System.out.println("MyView onPause");
    }

    @Override
    public void onStop() {
        System.out.println("MyView onStop");
    }

    @Override
    public void onDestroy() {
        System.out.println("MyView onDestroy");
    }

    @Override
    public void onRestart() {
        System.out.println("MyView onRestart");
    }
}
複製程式碼
  • 應用啟動時初始化ZRLifecycleDispatcher
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ZRLifecycleDispatcher.init(this);
    }
}
複製程式碼
  • 被觀察頁面實現ZRLifecycleRegistryOwner,並將要要觀察此頁面生命週期的觀察者物件加入集合
public class MainActivity extends Activity implements ZRLifecycleRegistryOwner {

    private ZRLifecycleRegistry lifecycleRegistry = new ZRLifecycleRegistry(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyView myView = findViewById(R.id.view_test);

        getLifecycle().addObserver(myView);

    }

    @Override
    public ZRLifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}
複製程式碼

具體工程程式碼可以從這裡獲取:CustomAACLifecycleDemo

結束

至此,關於AAC如何繫結頁面生命週期的原理講解結束。在上一篇文章如何繫結頁面生命週期(一)-Glide實現,介紹了Glide繫結生命週期的原理。兩種繫結頁面生命週期的方式,大家可以對比著看,相信肯定會對繫結頁面生命週期有更加深入的瞭解。

參考

Android Architecture Component -- Lifecycle 淺析

相關文章