Jetpack profile

define

  • Jetpack is a suite of libraries;
  • It mainly includes Architecture, Foundation, Behavior and UI.

The characteristics of

  1. Improved development efficiency and application quality, backward compatibility, can reduce crashes and memory leaks, allowing developers to focus more on the code that really matters;
  2. Eliminate boilerplate code and manage tedious activities such as background tasks, navigation, and lifecycle management.

AAC

  • The essence of Jetpack is Architecture, which stands for Android Architecture Component (AAC).
  • DataBinding, Lifecycle, LiveData, ViewModel, Navigation, Paging, Room, WorkManager, etc.

Lifecycle

  • It is used to help developers manage the lifecycle of activities and fragments. It is the basis of LiveData and ViewModel.

Introduction of depend on

  1. Non-androidx projects:
Implementation "android. Arch. Lifecycle: extensions: 1.1.1"Copy the code
  1. AndroidX project
Implementation 'androidx. Appcompat: appcompat: 1.2.0' / / appcompat dependence androidx fragments, Androidx. fragment will rely on ViewModel and LiveData, which will rely on Lifecycle;Copy the code
  1. Introducing dependencies in isolation
Build.gradle repositories {Google ()... } // build. Gradle dependencies {def lifecycle_version = "2.2.0" // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // LiveData implementation "Androidx. Lifecycle: lifecycle - livedata: $lifecycle_version" / / only Lifecycles (without the ViewModel or livedata) implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" // Saved state module for ViewModel implementation "Androidx. Lifecycle: lifecycle - viewmodel - savedstate: $lifecycle_version" / / lifecycle annotation processor annotationProcessor "Androidx. Lifecycle: lifecycle - compiler: $lifecycle_version" / / replace - if you use Java8, just replace with the lifecycle of the above - the compiler implementation "Androidx. Lifecycle: lifecycle - common - java8: $lifecycle_version" / / the following on-demand introduction / / optional - help implement LifecycleOwner Service Implementation "androidx lifecycle: lifecycle - service: $lifecycle_version" / / optional - ProcessLifecycleOwner to the whole process of the app Provide a lifecycle implementation "androidx. Lifecycle: lifecycle - process: $lifecycle_version" / / optional - ReactiveStreams support For LiveData implementation "androidx. Lifecycle: lifecycle - reactivestreams: $lifecycle_version" / / optional - Test helpers for LiveData testImplementation "androidx.arch.core:core-testing:lifecycle_version" }Copy the code
  • In fact, if Lifecycle is used only, all Lifecycle needs to do is introduce Lifecycle Runtime;

The basic use

  • Listen for the lifecycle in the Activity
class LifecycleDemoActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_lifecycle_demo) Lifecycle.addobServer (MyObserver()) ljyLogutil.d ("onCreate: main thread ID =${mainLooper.thread.id}") Globalscope.launch {val result1 = GlobalScope.async { delay(1000) 1 } val result2 = GlobalScope.async { delay(4000) 4 } val result = Result1.await () + result2.await() ljyLogutil.d ("onCreate: coroutine Thread ID =${thread.currentThread ().id},result =$result")}}} Class MyObserver: LifecycleObserver {// The observer method can take a parameter LifecycleOwner, which can be used either to get the current state or to continue adding observers. // If ON_ANY is annotated, we can also receive an Event, which is used to distinguish the Event. @OnLifecycleEvent(Lifecycle.Event.ON_ANY) fun onAny(owner: LifecycleOwner, event: Lifecycle.Event) { LjyLogUtil.d("LifecycleObserver.onAny:owner=" + owner.javaClass.name + ",event.name=" + event.name) }  @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) //fun onCreate() { fun onCreate(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onCreate:owner=${owner.javaClass.name}") GlobalScope.launch { Delay (5000) / / callback after checking the current life cycle State if (owner) lifecycle. The currentState. IsAtLeast lifecycle. State. (CREATED)) { LjyLogUtil. D (" LifecycleObserver onCreate: coroutines Thread id = ${Thread. CurrentThread () id} ")}}}}Copy the code
  • In real life, an MVP architecture would allow a Presenter to implement the LifecycleObserver interface, annotate the Lifecycle to be triggered on the corresponding method, and add it to Lifecycle as an observer in the Activity. The Presenter is automatically aware of the Activity lifecycle and executes methods.
  • As shown in the above code, you can check the current lifecycle state after a callback to avoid memory leaks

Custom LifecycleOwner

  • To implement a custom LifecycleOwner, you can use LifecycleRegistry, which is the implementation class for Lifecycle;
  • The following code also shows the relationship between the execution of each lifecycle method and the lifecycle state;
class MainActivity : Activity(), LifecycleOwner { private lateinit var mLifecycleRegistry: LifecycleRegistry override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mLifecycleRegistry = LifecycleRegistry(this)  mLifecycleRegistry.currentState = Lifecycle.State.CREATED lifecycle.addObserver(MyObserver2()) //startActivity(Intent(this, LifecycleDemoActivity::class.java)) } override fun onStart() { super.onStart() mLifecycleRegistry.currentState = Lifecycle.State.STARTED } override fun onResume() { super.onResume() mLifecycleRegistry.currentState = Lifecycle.State.RESUMED } override fun onPause() { super.onPause() mLifecycleRegistry.currentState = Lifecycle.State.STARTED } override fun onStop() { super.onStop() mLifecycleRegistry.currentState = Lifecycle.State.CREATED } override fun onDestroy() { super.onDestroy() mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED } override fun getLifecycle(): Lifecycle { return mLifecycleRegistry } } class MyObserver2 : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun onCreate(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onCreate:${owner.lifecycle.currentState}") } @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onStart(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onStart:${owner.lifecycle.currentState}") } @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onResume:${owner.lifecycle.currentState}") } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onPause:${owner.lifecycle.currentState}") } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onStop(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onStop:${owner.lifecycle.currentState}") } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy(owner: LifecycleOwner) { LjyLogUtil.d("LifecycleObserver.onDestroy:${owner.lifecycle.currentState}") } }Copy the code

ProcessLifecycleOwner

  • Monitor the Application lifecycle in a manner similar to that used in an Activity.
  • Using ProcessLifecycleOwner. The get (), for instance;

Example: Judge the App before and after it enters the background

  • Can pass registerActivityLifecycleCallbacks before (the callback) method, using a global variable in the callback do count, onActivityStarted () + 1, OnActivityStopped at -1 to determine the background switch.
  • ProcessLifecycleOwner can be used to directly obtain the application front and back switchover status.
/ / 1. Introduction of relying on implementation "androidx lifecycle: lifecycle - process: 2.3.1" / / 2. Class MyApplication: Application() { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(ApplicationLifecycleObserver()) } } class ApplicationLifecycleObserver  :LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onAppForeground(owner: LifecycleOwner){ LjyLogUtil.d("${owner.javaClass.simpleName}:app moved to foreground") } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onAppBackground(owner: LifecycleOwner){ LjyLogUtil.d("${owner.javaClass.simpleName}:app moved to background") } }Copy the code

Lifecycle principles and source code analysis

Lifecycle class

  • Lifecycle is the Lifecycle class that we use directly in development, so how does it work
Public abstract class Lifecycle {// addObserver @mainthread public abstract void addObserver(@nonnull LifecycleObserver) observer); // Remove the observer @mainThread public abstract void removeObserver(@nonnull LifecycleObserver observer); @mainThread @nonnull public abstract State getCurrentState(); @suppresswarnings ("WeakerAccess") public enum Event {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_PAUSE; @suppresswarnings ("WeakerAccess") public enum State {DESTROYED, INITIALIZED, DESTROYED} CREATED, STARTED, RESUMED; Public Boolean isAtLeast(@nonnull State State) {return compareTo(State) >= 0; }}}Copy the code

How does Lifecycle observe the Lifecycle of activities and fragments

  • In Android Support Library versions 26.1.0 and later, activities and fragments already implement the LifecycleOwner interface by default. LifecycleOwner can be understood as the observed;
ComponentActivity
  • Before the code is called ComponentActivity. GetLifecycle () to obtain Lifecycle instances, then presumably Lifecycle and ComponentActivity in ComponentActivity is some operation, Let’s look at the code for ComponentActivity. You can see that ComponentActivity implements the LifecycleOwner interface and returns the LifecycleRegistry instance at getLifecycle(). How similar to our previous custom LifecycleOwner code;
@RestrictTo(LIBRARY_GROUP) public class ComponentActivity extends Activity implements LifecycleOwner { private SimpleArrayMap<Class<? extends ExtraData>, ExtraData> mExtraDataMap = new SimpleArrayMap<>(); private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this); //1 @RestrictTo(LIBRARY_GROUP) public void putExtraData(ExtraData extraData) { mExtraDataMap.put(extraData.getClass(), extraData); } @Override @SuppressWarnings("RestrictedApi") protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ReportFragment.injectIfNeededIn(this); //2 } @CallSuper @Override protected void onSaveInstanceState(Bundle outState) { mLifecycleRegistry.markState(Lifecycle.State.CREATED); //3 super.onSaveInstanceState(outState); } @RestrictTo(LIBRARY_GROUP) public <T extends ExtraData> T getExtraData(Class<T> extraDataClass) { return (T) mExtraDataMap.get(extraDataClass); } @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; //4 } @RestrictTo(LIBRARY_GROUP) public static class ExtraData { } }Copy the code
  • But we see it only in onSaveInstanceState. Call the mLifecycleRegistry markState Lifecycle. State. (CREATED), not to us in case of change in the life cycle of Lifecycle status,
  • Call in its onCreate ReportFragment. InjectIfNeededIn (this), we will continue to look at how the ReportFragment
ReportFragment
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ReportFragment extends android.app.Fragment { public static void injectIfNeededIn(Activity activity) { if (Build.VERSION.SDK_INT >= 29) { LifecycleCallbacks.registerIn(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(); } } @SuppressWarnings("deprecation") 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); } } } static ReportFragment get(Activity activity) { return (ReportFragment) activity.getFragmentManager().findFragmentByTag( REPORT_FRAGMENT_TAG); } private ActivityInitializationListener mProcessListener; private void dispatchCreate(ActivityInitializationListener listener) { if (listener ! = null) { listener.onCreate(); } } private void dispatchStart(ActivityInitializationListener listener) { if (listener ! = null) { listener.onStart(); } } private void dispatchResume(ActivityInitializationListener listener) { if (listener ! = null) { listener.onResume(); } } @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(@NonNull Lifecycle.Event event) { if (Build.VERSION.SDK_INT < 29) { dispatch(getActivity(), event); } } void setProcessListener(ActivityInitializationListener processListener) { mProcessListener = processListener; } interface ActivityInitializationListener { void onCreate(); void onStart(); void onResume(); }... }Copy the code
  • From the code above you can see the status of dispatch way change Lifecycle, and dispatch again call LifecycleRegistry. HandleLifecycleEvent ()
LifecycleRegistry
  • Part of the code in LifecycleRegistry is as follows: Handler ElifecyCleEvent calls moveToState();
  • MoveToState () is responsible for moving to the new state, and finally sync() is used to synchronize the lifecycle state to all observers
  • My current state is called “backpass” or “backpass”, which is called “newest” in the mObserverMap, compared to my current state
  • BackwardPass () and backwardPass () calls its ObserverWithState static inner class. The dispatchEvent ()
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) { enforceMainThreadIfNeeded("handleLifecycleEvent"); moveToState(event.getTargetState()); } 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; } 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."); } // Iterate over the observer. The observer is stored in the mObserverMap. The mObserverMap adds the observer to the Activity by using getLifecycle().addobServer (). IsSynced (), if the state of the oldest observer is the same as the state of the newest observer, and both are the current state of ower, then the synchronization is over 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); } Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest(); if (! mNewEventOccurred && newest ! = null && mState.compareTo(newest.getValue().mState) > 0) { forwardPass(lifecycleOwner); } } mNewEventOccurred = false; } 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); final Event event = Event.upFrom(observer.mState); if (event == null) { throw new IllegalStateException("no event up from " + observer.mState); } observer.dispatchEvent(lifecycleOwner, event); popParentState(); } } } 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()))) { Event event = Event.downFrom(observer.mState); if (event == null) { throw new IllegalStateException("no event down from " + observer.mState); } pushParentState(event.getTargetState()); observer.dispatchEvent(lifecycleOwner, event); popParentState(); } } } 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 = event.getTargetState(); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code
ReflectiveGenericLifecycleObserver
  • The dispatchEvent () call again mLifecycleObserver. OnStateChanged (), the code is as follows
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver { private final Object mWrapped; private final CallbackInfo mInfo; ReflectiveGenericLifecycleObserver(Object wrapped) { mWrapped = wrapped; mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass()); } @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) { mInfo.invokeCallbacks(source, event, mWrapped); }}Copy the code
CallbackInfo
  • Minfo.invokecallbacks is called again in onStateChanged() above, with the following code
static class CallbackInfo { final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers; final Map<MethodReference, Lifecycle.Event> mHandlerToEvent; CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) { mHandlerToEvent = handlerToEvent; mEventToHandlers = new HashMap<>(); for (Map.Entry<MethodReference, Lifecycle.Event> entry : handlerToEvent.entrySet()) { Lifecycle.Event event = entry.getValue(); List<MethodReference> methodReferences = mEventToHandlers.get(event); if (methodReferences == null) { methodReferences = new ArrayList<>(); mEventToHandlers.put(event, methodReferences); } methodReferences.add(entry.getKey()); } } @SuppressWarnings("ConstantConditions") void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) { invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target); invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event, target); } private static void invokeMethodsForEvent(List<MethodReference> handlers, LifecycleOwner source, Lifecycle.Event event, Object mWrapped) { if (handlers ! = null) { for (int i = handlers.size() - 1; i >= 0; i--) { handlers.get(i).invokeCallback(source, event, mWrapped); }}}}Copy the code
MethodReference
  • InvokeCallbacks () and indirect invocation MethodReference. InvokeCallback, its code is as follows
static final class MethodReference { final int mCallType; final Method mMethod; MethodReference(int callType, Method method) { mCallType = callType; mMethod = method; mMethod.setAccessible(true); } void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) { //noinspection TryWithIdenticalCatches try { switch (mCallType) { case CALL_TYPE_NO_ARG: mMethod.invoke(target); break; case CALL_TYPE_PROVIDER: mMethod.invoke(target, source); break; case CALL_TYPE_PROVIDER_WITH_EVENT: mMethod.invoke(target, source, event); break; } } catch (InvocationTargetException e) { throw new RuntimeException("Failed to call observer method", e.getCause()); } catch (IllegalAccessException e) { throw new RuntimeException(e); }}}Copy the code
  • So to summarize, in classes that implement the LifecycleObserver interface, annotated methods and events are saved, and the corresponding method of the event is called through reflection

I am Jinyang, if you want to advance and learn more about dry goods, welcome to follow the wechat public account “jinyang said” to receive my latest articles