Android Jetpack之AAC Lifecycle你用對了嗎?(一)

Android Jetpack是2018年穀歌I/O發佈的一系列輔助android開發者的實用工具,合稱Jetpack,以幫助開發者構建出色的 Android 應用。Android Jetpack 組件覆蓋以下 4 個方面:Architecture、Foundation、Behavior 以及 UI。

Lifecycle則是Architecture Compinents官方架構組件之一。Lifecycle的推出讓開發者能夠在非Fragment和activity中也能感知到fragment和activity生命週期, 開發者也能更專注於處理邏輯的本身,而很多嵌套在Activity/Fragment中的一些膠水代碼,也能很好的剝離出來,避免因無法感知到生命週期存在的內存泄露問題。

引入Lifecycle

這裏我們使用android X引入方式

 api 'androidx.appcompat:appcompat:1.1.0'

appcompat默認已經內置lifecycle-common組件,我們無需單獨引用了。

如需要指定java8可添加如下引用

 api 'androidx.lifecycle:lifecycle-common-java8:2.1.0'

Support版本的引入方式

注:support版本默認也有引入lifecycle,這裏添加一個註解編譯即可

implementation "com.android.support:appcompat-v7:28.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
//java8使用引入
implementation "android.arch.lifecycle:common-java8:1.1.1"

生命週期回調

java7中的用法

public interface LifecycleObserverIml extends LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.On_CREATE)
    void onCreate();

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart();

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onResume();

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void onPause();

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop();

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy();
}

java8中的用法

public interface LifecycleObserverIml8 extends DefaultLifecycleObserver {

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onStart(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onResume(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onPause(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onStop(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onDestroy(@NonNull LifecycleOwner owner) {
    }
}

在Activity/Frament中進行綁定

綁定

getLifecycle().addObserver(lifecycleObserver);

解綁

getLifecycle().removeObserver(lifecycleObserver)

使用上是不是既簡單又實用呢?那麼問題就來了,如果我既要在Fragment中使用也要在Activity中使用,能不能像Glide一樣,傳進來的是什麼級別上下文,內部自動綁定對應的上下文級別的生命週期呢?

答案是肯定的!我們來手擼一個綁定的輔助類

public class LifecycleBindHelper {


    private LifecycleOwner lifecycleOwner;
    // 生命週期回調
    private ArrayMap<Object, LifecycleObserver> lifecyleCallbacks = new ArrayMap<>();


    public static LifecycleBindHelper with(Object object) {
        return new LifecycleBindHelper(object);
    }

    public static LifecycleBindHelper with(AppCompatActivity object) {
        return new LifecycleBindHelper(object);
    }

    public static LifecycleBindHelper with(Fragment object) {
        return new LifecycleBindHelper(object);
    }


    private AppLifecycleBindHelper(Object object) {
        if (object != null && object instanceof LifecycleOwner) {
            lifecycleOwner = (LifecycleOwner) object;
        }
    }

    public LifecycleBindHelper addLifecyleCallback(LifecycleObserver lifecycleObserver) {
        if (hasRefrence() && lifecycleObserver != null) {
            lifecyleCallbacks.put(lifecycleObserver, lifecycleObserver);
            lifecycleOwner.getLifecycle().addObserver(lifecycleObserver);
        }
        return this;
    }

    public LifecycleBindHelper removeLifecyleCallback(LifecycleObserver lifecycleObserver) {
        if (hasRefrence() && lifecycleObserver != null) {
            lifecyleCallbacks.remove(lifecycleObserver);
            this.lifecycleOwner.getLifecycle().removeObserver(lifecycleObserver);
        }
        return this;
    }

    private LifecycleObserver[] getLifecycleCallbacks() {
        LifecycleObserver[] callbacks = new LifecycleObserver[lifecyleCallbacks.values().size()];
        lifecyleCallbacks.values().toArray(callbacks);
        return callbacks;
    }


    public boolean hasRefrence() {
        return null != this.lifecycleOwner;
    }

    /**
     * 清除所有的回調(只能清除當前對象添加的回調,其他方式添加的回調監聽可以通過手動移除形式)
     */
    public void clearAll() {
        if (!hasRefrence()) {
            return;
        }
        for (LifecycleObserver lifecycleObserver : getLifecycleCallbacks()) {
            removeLifecyleCallback(lifecycleObserver);
        }
        build();
    }

    /**
     * 構建完成,不需要進行使用時調用
     */
    public void build() {
        lifecyleCallbacks.clear();
        this.lifecycleOwner = null;
    }


}

在這裏插入圖片描述

如何利用好lifecycle

愈演愈烈的MVP、MVVM開發模式中,我們會將Activity/Fragment中的原有代碼邏輯拆散到各個模塊中,好處是各自模塊負責管理自己的職責,但缺點對生命週期感知幾乎是沒有,這樣就會有導致有很多膠水代碼,每個模塊邏輯就像是補丁一樣和原始頁面緊緊關聯在一起。

以MVP開發模式爲例,我們如何增強生命週期感知能力呢.
利用剛剛封裝好的LifecycleBindHelper,我們針對Presenter封裝一層BasePresenter。

使用案例1:登錄模塊

代碼如下:

class BasePresenter implements LifecycleObserverIml {
    private LifecycleBindHelper lifecycleBindHelper;

    private static final String TAG = "BasePresenter";

    private FragmentActivity mActivity;
    private Fragment mFragment;

    public BasePresenter(FragmentActivity context) {
        bindLifecycleOwner(context);
    }

    public BasePresenter(Fragment fragment) {
        bindLifecycleOwner(fragment);
    }

    private void bindLifecycleOwner(Object lifecycleOwner) {
        if (lifecycleBindHelper != null && lifecycleBindHelper.hasReference()) {
            lifecycleBindHelper.clearAll();
        }
        if (lifecycleOwner instanceof FragmentActivity) {
            this.mActivity = (FragmentActivity) lifecycleOwner;
        }
        if (lifecycleOwner instanceof Fragment) {
            this.mFragment = (Fragment) lifecycleOwner;
            this.mActivity = this.mFragment.getActivity();
        }
        lifecycleBindHelper = LifecycleBindHelper.with(lifecycleOwner).
                addLifecycleCallback(this);
    }

    public FragmentActivity getActivity() {
        return mActivity;
    }

    @Override
    public void onStart() {
        Log.e(TAG, "onStart: ");
    }

    @Override
    public void onResume() {
        Log.e(TAG, "onResume: ");
    }

    @Override
    public void onPause() {
        Log.e(TAG, "onPause: ");
    }

    @Override
    public void onStop() {
        Log.e(TAG, "onStop: ");
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: ");
        if (lifecycleBindHelper.hasReference()) {
            lifecycleBindHelper.clearAll();
        }
    }
}

這樣我們就能很好在Presenter處理生命週期問題了

使用案例2:播放器場景

在沒有使用lifecycle時,我們通常是這樣使用的

public class MainPlayerActivity extends AppCompatActivity {
    MediaPlayer mediaPlayer;

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

    public void initPlayer() {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(Environment.getExternalStorageDirectory() + "/demo.mp4");
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void onResume() {
        super.onResume();
        mediaPlayer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mediaPlayer.pause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop();
    }
}

當Activity中的生命週期變更後,我們也要同步去變更播放器的狀態,看到這裏,可能會說這沒啥問題呀!設想一下,假設我們有2個甚至更多頁面是否都得這樣處理一遍呢?

我們來看看使用了lifycycle之後怎樣處理的

public class MainPlayerNewActivity extends AppCompatActivity {
    PlayerManager playerManager;

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

    public void initPlayer() {
        playerManager = new PlayerManager(this);
        playerManager.setDataSource(
        Environment.getExternalStorageDirectory() + "/demo.mp4");
    }
}
public class PlayerManager extends BasePresenter {
    MediaPlayer mediaPlayer;

    public PlayerManager(FragmentActivity context) {
        super(context);
        mediaPlayer = new MediaPlayer();
    }

    public void setDataSource(String path) {

        try {
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        mediaPlayer.start();
    }

    @Override
    public void onPause() {
        super.onPause();
        mediaPlayer.pause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop();
    }
}

可以發現Activity中的代碼是不是少了很多,並且PlayerManager就可以在各個頁面進行復用了,並且在外部使用時,也不用關心生命週期變更的問題了。
在這裏插入圖片描述

源碼解析

源碼分析以Android X爲基礎

綁定觀察者

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
}

從上述代碼我們可以看到我們在外部調用getLifecycle(),實際上獲取的是LifecycleRegistry類對象。

public class LifecycleRegistry extends Lifecycle {
//省略相關代碼.....
}

LifecycleRegistry實現了Lifecycle接口,提供了增加/刪除的觀察者接口函數

public abstract class Lifecycle {

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    AtomicReference<Object> mInternalScopeRef = new AtomicReference<>();
    
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);
    
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);
    
    @MainThread
    @NonNull
    public abstract State getCurrentState();
}

通知觀察者

public class LifecycleRegistry extends Lifecycle {
//省略相關代碼.....

 public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);
        moveToState(next);
    }

    private void moveToState(State next) {
        if (mState == next) {
            return;
        }
        mState = next;
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }
     // happens only on the top of stack (never in reentrance),
    // so it doesn't have to take in account parents
    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;
    }
    //省略相關代碼.....
    
}

通過源碼我們可以發現,所有的觀察者所接受的事件都是由**handleLifecycleEvent(@NonNull Lifecycle.Event event)**函數來驅動,最後分發到forwardPass和backwardPass這兩個函數來進行分發和同步的操作。

forwardPass() 遍歷觀察者集合,當觀察者生命週期狀態小於當前生命週期狀態時 分發事件

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

backwardPass() 遍歷觀察者集合,當觀察者生命週期狀態大於當前生命週期狀態時 分發事件

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

那麼問題就來了,在哪發起調用 handleLifecycleEvent() 函數呢?我們查看ComponentActivity源碼似乎只對外提供了一個getLifecycle函數

一番查找後在ComponentActivity中的onCreate函數發現這行代碼

public class ComponentActivity extends Activity implements
        LifecycleOwner,
        KeyEventDispatcher.Component {
        
    @SuppressLint("RestrictedApi")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
    }
} 

把ReportFragment添加到了ComponentActivity中

public class ReportFragment extends Fragment {
    private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"
            + ".LifecycleDispatcher.report_fragment_tag";

    public static void injectIfNeededIn(Activity activity) {
         fragments for activities
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            // Hopefully, we are the first to make a transaction.
            manager.executePendingTransactions();
        }
    }
}    

這時往下看ReportFragment中的代碼,頓時就一目瞭然了

public class ReportFragment extends Fragment {
    
    @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;
    }

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

}

總結: LifecycleRegistry作爲Lifecycle的實現類,將我們的添加的觀察者對象存放至觀察者集合中,由代理的ReportFragment作爲生命週期代理的存在,當生命週期發生變更時,會通知LifecycleRegistry有變,最後LifecycleRegistry來通知所有的觀察者,所以我們在外部就可以輕鬆的感知到生命週期了。

最後LifecycleObserver、Lifecycle、LifecycleRegistry、ComponentActivity、
ReportFragment之間的關聯可以總結爲如下圖。
在這裏插入圖片描述

注:關於Jetpack AAC架構組件系列後續還會分析詳解,可以關注公衆號,早上八點不定時更新。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章