The source code and trick of Lifecycle-Aware of Android Architecture Components

Keywords: Fragment Google Android SDK

See my brief book https://www.jianshu.com/u/c717eefe3f42

One background

google's Architecture Components Components(lz abbreviated AAC) has been out for a long time, but has not had time to read the source code, take advantage of the recent gap, read the source code of AAC, share the understanding of reading.

What is AAC?

In fact, AAC is an app development framework proposed by google, which should be based on Lifecycle-Aware. Before that, our group developed the mvvm + data binding mode. In this mode, we often need to release resources in the anti-registration ViewModel when we are fragment on Destroy or onPause. We need to make callbacks at several levels, such as ViewModel > adapter > fragment ViewModel > fragment. Lifecycle-Aware has an advantage that it is bound to the life cycle and handled directly in the corresponding life cycle logic. Of course, this is also a decoupling method, which is implemented in the observer mode.

Source Code of Three Lifecycle-Aware

Observer model

a Look for access first. Usually we use Lifecycle-Aware in this way.
Lifecycle lifecycle = lifecycleOwner.getLifecycle();
        lifecycle.addObserver((GenericLifecycleObserver) (source, event) -> {
           
        });
The addObserver method of b lifecycle is as follows:
@Override
    public void addObserver(LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

      //Added
        if (previous != null) {
            return;
        }

       //Second reentry
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;

        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(mLifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

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

The mLifecycle Observer. onStateChanged (owner, event) method is invoked by a single sentence of mLifecycle Owner (upEvent) (mLifecycle Observer. mState); that is, the void onStateChanged (Lifecycle Owner source, Lifecycle. Event event) method of the Generic Lifecycle Observer that we mentioned above.

c Specifically, Observer WithState Observer = new Observer WithState (observer, initial State);
 ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);
            mState = initialState;
        }
d Packing Observer is Generic Lifecycle Observer. Here we note the use of reflection. When colleagues use it, a bug they encounter is crash, because this version of the obfuscation file does not keep the Lifecycling class.
static GenericLifecycleObserver getCallback(Object object) {
        if (object instanceof GenericLifecycleObserver) {
            return (GenericLifecycleObserver) object;
        }
        //noinspection TryWithIdenticalCatches
        try {
            final Class<?> klass = object.getClass();
            Constructor<? extends GenericLifecycleObserver> cachedConstructor = sCallbackCache.get(
                    klass);
            if (cachedConstructor != null) {
                return cachedConstructor.newInstance(object);
            }
            cachedConstructor = getGeneratedAdapterConstructor(klass);
            if (cachedConstructor != null) {
                if (!cachedConstructor.isAccessible()) {
                    cachedConstructor.setAccessible(true);
                }
            } else {
                cachedConstructor = sREFLECTIVE;
            }
            sCallbackCache.put(klass, cachedConstructor);
            return cachedConstructor.newInstance(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
e In addition, the sync() method is as follows:
// happens only on the top of stack (never in reentrance),
    // so it doesn't have to take in account parents
    private void sync() {
        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();
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass();
            }
        }
        mNewEventOccurred = false;
    }
f If it is in the initialization period, onResume and forward Pass (), the life cycle before the positive callback. onPause and later, reverse callback backwardPass().

At this time, the special data structure FastSafeIterableMap has a comparative advantage in supporting forward and backward traversal. If the current state is less than the previous state, the forward callback, otherwise the reverse callback. The processing here is similar to the fragment lifecycle state. State machine, paste the official stolen map:

image.png

trick 1 no ui fragment binding life cycle

a At present, Android sdk 26.1.0 supports Lifecycle-Aware. Let's start with Activity. Lifecycle-Aware's initialization logic is SupportActivity, BaseFragmentActivity Api14 extends SupportActivity. We can see that the lowest version is sdk 14, and finally inherit the most familiar subclass is FragmentActivity extends BaseFragmentActivity Api16.
image.png
b Here is a common routine throughout AAC, using ui-free fragments to synchronize the activity lifecycle. The code for the specific report fragment injection is as follows.
 public static void injectIfNeededIn(Activity activity) {
        // ProcessLifecycleOwner should always correctly work and some activities may not extend
        // FragmentActivity from support lib, so we use framework 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();
        }
    }
c code is relatively simple in create and other callbacks, dispatch corresponding events.
 @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

Lifecycle Registry Owner or Lifecycle Owner activity callbacks for corresponding implementations

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);
            }
        }
    }
 public void handleLifecycleEvent(Lifecycle.Event event) {
        mState = getStateAfter(event);
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }

This will synchronize the state.

sample trick 2

Another small point is the use of ContentProvider on Create to bind activity and fragment lifecycles in BaseSample, which is not detailed.

public class ProcessLifecycleOwnerInitializer extends ContentProvider {
    @Override
    public boolean onCreate() {
        LifecycleDispatcher.init(getContext());
        ProcessLifecycleOwner.init(getContext());
        return true;
    } 
  . . . 
}
image.png

Continue to steal, the left part is the current callback.

Posted by Dowdy on Tue, 11 Dec 2018 13:24:06 -0800