【AAC 系列二】深入理解架构组件的基石:Lifecycle

640?wx_fmt=jpeg
Photo by Kelly Sikkema on Unsplash

这是程序亦非猿的第 85 期分享。


作者 l 程序亦非猿 

来源 l 程序亦非猿(ID:chengxuyifeiyuan)

转载请联系授权(微信ID:ONE-D-PIECE)

时不时 8:40 更新

0. 序言


你好,我是 菩提本无树, 程序亦非猿。

本文是深入理解 Android Archicture Components (后称AAC) 系列文章的第二篇。

开篇看这里:【AAC 系列一】Android 应用架构新时代来临!


在前文,我就提到 Android Architecture Components ,是一个帮助开发者设计 健壮 、 可测试 且 可维护的一系列库的集合。


Lifecycle 就是 AAC 中的一员,它能够帮助我们方便的管理 Activity 以及 Fragment 的生命周期


本文带大家深入了解 Lifecycle


注意:本文基于 Lifecycle 1.1.1 版本,Android API 26 ,依赖如下图。

640?wx_fmt=png

并假设读者对 Lifecycle 有基本的了解,我绘制了一个基本的类图,如果对于下面类图所涉及到的类都还算了解则可以继续阅读下去,如果完全不知道,建议阅读一些教程先

640?wx_fmt=png

1. Lifecycle 使用基础

在 AppCompatActivity 里我们可以通过 getLifecycle() 方法拿到 Lifecycle, 并添加 Observer 来实现对 Activity 生命周期的监听。

一个简单的使用例子如下:

 
 
public class MainActivity extends AppCompatActivity {	
	
    private static final String TAG = "MainActivity";	
	
    @Override	
    protected void onCreate(Bundle savedInstanceState) {	
        super.onCreate(savedInstanceState);	
        setContentView(R.layout.activity_main);	
        testLifecycle();	
    }	
	
    private void testLifecycle() {	
        getLifecycle().addObserver(new LifecycleObserver() {	
	
            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)	
            void onResume(){	
                Log.d(TAG, "LifecycleObserver onResume() called");	
            }	
        });	
    }	
	
    @Override	
    protected void onResume() {	
        super.onResume();	
        Log.d(TAG, "onResume: ");	
    }	
}

启动 MainActivity 就可以看到如下日志:

 
 
D/MainActivity: onResume: 	
D/MainActivity: LifecycleObserver onResume() called

日志说明我们通过上述代码确实实现了监听生命周期的功能。

那么问题来了,这是怎么做到的?

我把这个问题拆分成了两块:

  1. 生命周期的感知问题: 是什么感知了Activity的生命周期 ?

  2. 注解方法的调用问题: 是什么调用了我们使用注解修饰的方法 ?


2. 感知生命周期的原理

2.1 初现端倪 ReportFragment

我通过调试堆栈发现了一个叫做 ReportFragment 的类,非常可疑,遂跟踪之。

注意:Debug 查看堆栈是阅读源码手段中最常用最简单最好用最亲民的方法,没有之一,每个人都应该熟练掌握。

来看看这个类都写了什么:

 
 
public class ReportFragment extends Fragment {	
	
    private static final String REPORT_FRAGMENT_TAG = "android.arch.lifecycle"	
            + ".LifecycleDispatcher.report_fragment_tag";	
    //注入 Fragment 的方法	
    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();	
        }	
    }	
    //...	
    @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;	
    }	
    //分发生命周期事件给 LifecycleRegistryOwner 的 Lifecycle 或者 LifecycleRegistry	
    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 在发挥作用,Lifecycle 利用了 Fragment 来实现监听生命周期,并在生命周期回调里调用了内部 dispatch 的方法来分发生命周期事件。(怎么分发后面讲)


2.2 幕后“黑手” SupportActivity

从方法来看注入 Fragment 的方法应该是调用 injectIfNeededIn(Activity) 的地方了。

在通过搜索 发现 SupportActivity 调用了该方法。(API 28 的版本是 ComponentActivity ,代码实现没什么差别)

 
 
public class SupportActivity extends Activity implements LifecycleOwner, Component {	
	
    //拥有一个 LifecycleRegistry	
    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);	
	
    protected void onCreate(@Nullable Bundle savedInstanceState) {	
        super.onCreate(savedInstanceState);	
        //在 onCreate 里注入了 ReportFragment	
        ReportFragment.injectIfNeededIn(this);	
    }	
	
    @CallSuper	
    protected void onSaveInstanceState(Bundle outState) {	
        this.mLifecycleRegistry.markState(State.CREATED);	
        super.onSaveInstanceState(outState);	
    }	
	
    public Lifecycle getLifecycle() {	
        return this.mLifecycleRegistry;	
    }	
}

可以看到 SupportActivity 内部包含了一个 LifecycleRegistry ,并实现了 LifecycleOwner , 并且在 onCreate 方法里 调用了 ReportFragment.injectIfNeededIn(this); 注入了 ReportFragment 。


LifecycleRegistry 是 Lifecycle 的实现,并负责管理 Observer ,在上面【2】章节的 dispatch 方法中已经看到了该类的出现,它的 handleLifecycEvent 接受了生命周期的回调。


2.3 Lifecycle 的生命周期事件与状态的定义

这小节补充一下 Lifecycle 的回调与 Activity 、Fragment 的生命周期对标相关知识,后面分析会出现。

Lifecycle 中定义了 Event : 表示生命周期事件, State : 表示当前状态。

2.3.1 Lifecycle.Event

Lifecycle 定义的生命周期事件,与 Activity 生命周期类似。

 
 
  public enum Event {	
      ON_CREATE,	
      ON_START,	
      ON_RESUME,	
      ON_PAUSE,	
      ON_STOP,	
      ON_DESTROY,	
      ON_ANY	
  }
2.3.2 Lifecycle.State

State 表示当前组件的生命周期状态。

 
 
    /**	
     * Lifecycle states. You can consider the states as the nodes in a graph and	
     * {@link Event}s as the edges between these nodes.	
     */	
    public enum State {	
        DESTROYED,	
        INITIALIZED,	
        CREATED,	
        STARTED,	
        RESUMED;	
        public boolean isAtLeast(@NonNull State state) {	
            return compareTo(state) >= 0;	
        }	
    }
2.3.3 Event 与 State 的关系:

640?wx_fmt=png

(图1.图来源见【8.2】)


2.4 小结

通过研究我们发现,SupportActivity 在 onCreate 方法里注入了 ReportFragment ,通过 Fragment 的机制来实现生命周期的监听

实际上利用 Fragment 监听 Activity 生命周期的功能在开源社区由来已久, Lifecycle 并非原创,Lifecycle 的出现算是把这个实现官方化了。

相比于第三方的实现,嵌入到 Android 源码中的实现对开发者来说是非常有好处的,即屏蔽了细节,又降低了使用难度

3. 注解方法被调用的原理

OnLifecycleEvent 注解:

 
 
@Retention(RetentionPolicy.RUNTIME)	
@Target(ElementType.METHOD)	
public @interface OnLifecycleEvent {	
    Lifecycle.Event value();	
}

看到有 RetentionPolicy.RUNTIME 修饰,我就猜测它是靠反射来实现了,不过还是看下具体实现验证下吧。

之前在了解完生命周期监听的原理的同时,我们也看到了生命周期事件的接收者 LifecycleRegistry ,是它的 handleLifecycleEvent() 接收了事件,我们继续追踪。

 
 
  /**	
   * Sets the current state and notifies the observers.	
   * Note that if the {@code currentState} is the same state as the last call to this method,	
   * calling this method has no effect.	
   */	
  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;	
  }

其实从方法注释就能看出来了,就是它处理了状态并通知了 observer 。

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

getStateAfter() 这个方法根据当前 Event 获取对应的 State ,细看其实就是 【2.3.3】中那个图的代码实现。

接下去看 sync() 方法:

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

sync 方法里对比了当前 mState 以及上一个 State ,看是应该前移还是后退,这个对应了生命周期的前进跟后退,打个比方就是从 onResume -> onPause (forwardPass),onPause -> onResume (backwardPass),拿 backwardPass() 举例吧。(forwardPass方法处理类似)

 
 
  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()))) {	
              //调用 downEvent 获取更前面的 Event	
              Event event = downEvent(observer.mState);	
              pushParentState(getStateAfter(event));	
              //分发 Event 	
              observer.dispatchEvent(lifecycleOwner, event);	
              popParentState();	
          }	
      }	
  }	
  	
  private static Event downEvent(State state) {	
      switch (state) {	
          case INITIALIZED:	
              throw new IllegalArgumentException();	
          case CREATED:	
              return ON_DESTROY;	
          case STARTED:	
              return ON_STOP;	
          case RESUMED:	
              return ON_PAUSE;	
          case DESTROYED:	
              throw new IllegalArgumentException();	
      }	
      throw new IllegalArgumentException("Unexpected state value " + state);	
  }

通过源码可以看到, backwardPass() 方法调用 downEvent 获取往回退的目标 Event。

可能比较抽象,举个例子,在 onResume 的状态,我们按了 home,这个时候就是 RESUMED 的状态变到 STARTED 的状态,对应的要发送的 Event 是 ON_PAUSE,这个就是 backwardPass() 的逻辑了

如果前面的代码都是引子的话,我们最终看到了一丝分发的痕迹了—— observer.dispatchEvent(lifecycleOwner, event)


 
 
static class ObserverWithState {	
    State mState;	
    GenericLifecycleObserver mLifecycleObserver;	
	
    ObserverWithState(LifecycleObserver observer, State initialState) {	
        mLifecycleObserver = Lifecycling.getCallback(observer);	
        mState = initialState;	
    }	
	
    void dispatchEvent(LifecycleOwner owner, Event event) {	
        State newState = getStateAfter(event);	
        mState = min(mState, newState);	
        //这里	
        mLifecycleObserver.onStateChanged(owner, event);	
        mState = newState;	
    }	
}

可以看到最后调用了 GenericLifecycleObserver.onStateChanged() 方法,再跟。

 
 
class ReflectiveGenericLifecycleObserver implements GenericLifecycleObserver {	
    //mWrapped 是 我们的 Observer	
    private final Object mWrapped;	
    //反射 mWrapped 获取被注解了的方法	
    private final CallbackInfo mInfo;	
    @SuppressWarnings("WeakerAccess")	
    static final Map<Class, CallbackInfo> sInfoCache = new HashMap<>();	
	
    ReflectiveGenericLifecycleObserver(Object wrapped) {	
        mWrapped = wrapped;	
        mInfo = getInfo(mWrapped.getClass());	
    }	
	
    @Override	
    public void onStateChanged(LifecycleOwner source, Event event) {	
        invokeCallbacks(mInfo, source, event);	
    }	
    	
    private void invokeCallbacks(CallbackInfo info, LifecycleOwner source, Event event) {	
        invokeMethodsForEvent(info.mEventToHandlers.get(event), source, event);	
        invokeMethodsForEvent(info.mEventToHandlers.get(Event.ON_ANY), source, event);	
    }	
  	
    private void invokeMethodsForEvent(List<MethodReference> handlers, LifecycleOwner source,	
            Event event) {	
        if (handlers != null) {	
            for (int i = handlers.size() - 1; i >= 0; i--) {	
                MethodReference reference = handlers.get(i);	
                invokeCallback(reference, source, event);	
            }	
        }	
    }	
    //最后走到 invokeCallback 这里	
    private void invokeCallback(MethodReference reference, LifecycleOwner source, Event event) {	
        //noinspection TryWithIdenticalCatches	
        try {	
            switch (reference.mCallType) {	
                case CALL_TYPE_NO_ARG:	
                    reference.mMethod.invoke(mWrapped);	
                    break;	
                case CALL_TYPE_PROVIDER:	
                    reference.mMethod.invoke(mWrapped, source);	
                    break;	
                case CALL_TYPE_PROVIDER_WITH_EVENT:	
                    reference.mMethod.invoke(mWrapped, source, event);	
                    break;	
            }	
        } catch (InvocationTargetException e) {	
            throw new RuntimeException("Failed to call observer method", e.getCause());	
        } catch (IllegalAccessException e) {	
            throw new RuntimeException(e);	
        }	
    }	
  	
    private static CallbackInfo getInfo(Class klass) {	
        CallbackInfo existing = sInfoCache.get(klass);	
        if (existing != null) {	
            return existing;	
        }	
        existing = createInfo(klass);	
        return existing;	
    }	
    	
    //通过反射获取 method 信息	
    private static CallbackInfo createInfo(Class klass) {	
        //...	
        Method[] methods = klass.getDeclaredMethods();	
	
        Class[] interfaces = klass.getInterfaces();	
        for (Class intrfc : interfaces) {	
            for (Entry<MethodReference, Event> entry : getInfo(intrfc).mHandlerToEvent.entrySet()) {	
                verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass);	
            }	
        }	
	
        for (Method method : methods) {	
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);	
            if (annotation == null) {	
                continue;	
            }	
            Class<?>[] params = method.getParameterTypes();	
            int callType = CALL_TYPE_NO_ARG;	
            if (params.length > 0) {	
                callType = CALL_TYPE_PROVIDER;	
                if (!params[0].isAssignableFrom(LifecycleOwner.class)) {	
                    throw new IllegalArgumentException(	
                            "invalid parameter type. Must be one and instanceof LifecycleOwner");	
                }	
            }	
            Event event = annotation.value();	
            //...	
            MethodReference methodReference = new MethodReference(callType, method);	
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);	
        }	
        CallbackInfo info = new CallbackInfo(handlerToEvent);	
        sInfoCache.put(klass, info);	
        return info;	
    }	
	
    @SuppressWarnings("WeakerAccess")	
    static class CallbackInfo {	
        final Map<Event, List<MethodReference>> mEventToHandlers;	
        final Map<MethodReference, Event> mHandlerToEvent;	
	
        CallbackInfo(Map<MethodReference, Event> handlerToEvent) {	
            //...	
        }	
    }	
	
    static class MethodReference {	
        final int mCallType;	
        final Method mMethod;	
	
        MethodReference(int callType, Method method) {	
            mCallType = callType;	
            mMethod = method;	
            mMethod.setAccessible(true);	
        }	
    }	
	
    private static final int CALL_TYPE_NO_ARG = 0;	
    private static final int CALL_TYPE_PROVIDER = 1;	
    private static final int CALL_TYPE_PROVIDER_WITH_EVENT = 2;	
}


这个类的代码比较多,不过也不复杂。可以看到最后代码走到了invokeCallback() ,通过反射调用了方法。


而这个方法是 createInfo() 方法中反射遍历我们注册的 Observer 的方法找到的被 OnLifecycleEvent 注解修饰的方法,并且按 Event 类型存储到了 info.mEventToHandlers 里。


到这里整个链路就清晰了,我们在 Observer 用注解修饰的方法,会被通过反射的方式获取,并保存下来,然后在生命周期发生改变的时候再找到对应 Event 的方法,通过反射来调用方法


注意:源码中还有一些细节比较繁琐,比如怎么获取的方法,怎么包装的 Observer ,State 的管理以及存储等,就不在这里展开了,有兴趣的自行了解。


4. 图解 Lifecycle

如果被代码绕晕了,也没关系,我画了类图以及时序图,帮助大家理解,配合着类图跟时序图看代码,会容易理解很多。


4.1 Lifecycle 相关原理类的 UML 图

核心类 UML 图整理如下:

640?wx_fmt=jpeg
(图2. Lifecycle-UML图)


4.1 Lifecycle 原理时序图

图中起始于 onCreate ,顺便利用 onCreate 描绘整个流程。(其他生命周期原理一样,不重复画了)

640?wx_fmt=jpeg

(图3. Lifecycle 时序图)


4.3 Lifecycle State 与 Event 的关系图

图展示了 State 与 Event 的关系,以及随着生命周期走向它们发生的变化。

640?wx_fmt=png
(图4. State 与 Event 的关系图)


5. Lifecycle 的实战应用


好了,重点的原理我们分析完毕了,如果看一遍没有理解,就多看几遍。这个小节来讲讲 Lifecycle 的实战应用。


Lifecycle 的应用场景非常广泛,我们可以利用 Lifecycle 的机制来帮助我们将一切跟生命周期有关的业务逻辑全都剥离出去,进行完全解耦,比如视频的暂停与播放,Handler 的消息移除,网络请求的取消操作,Presenter 的 attach&detach View 等等,并且可以以一个更加优雅的方式实现,还我们一个更加干净可读的 Activity & Fragment。


下面举个简单的例子:

5.1 自动移除 Handler 的消息:LifecycleHandler


我们担心 Handler 会导致内存泄露,通常会在 onDestroy 里移除消息,写多了烦,但是结合 Lifecycle ,我们可以写出一个 lifecycle-aware 的 Handler,自动在 onDestroy 里移除消息,不再需要写那行样板代码

代码实现如下:

640?wx_fmt=png

该代码已经包含在我的开源库 Pandora 里了,可以访问:https://github.com/AlanCheen/Pandora ,直接依赖使用,欢迎 star。


5.2 给 ViewHolder 添加 Lifecycle 的能力


有些 App 会有长列表的页面,里面塞了各种不用样式的 Item,通常会用 RecyclerView 来实现,有时候部分 Item 需要获知生命周期事件,比如包含播放器的 Item 需要感知生命周期来实现暂停/重播的功能,借助 Lifecycle 我们可以实现。


具体实现可以参考我的开源库 Flap:https://github.com/AlanCheen/Flap 。


6. 知识点梳理汇总


  1. Lifecycle 库通过在 SupportActivity 的 onCreate 中注入 ReportFragment 来感知发生命周期;

  2. Lifecycle 抽象类,是 Lifecycle 库的核心类之一,它是对生命周期的抽象,定义了生命周期事件以及状态,通过它我们可以获取当前的生命周期状态,同时它也奠定了观察者模式的基调;(我是党员你看出来了吗:-D)

  3. LifecycleOwner ,描述了一个拥有生命周期的组件,可以自己定义,不过通常我们不需要,直接使用 AppCompatActivity 等即可;

  4. LifecycleRegistry 是Lifecycle的实现类,它负责接管生命周期事件,同时也负责Observer` 的注册以及通知;

  5. ObserverWithState ,是 Observer 的一个封装类,是它最终 通过 ReflectiveGenericLifecycleObserve 调用了我们用注解修饰的方法;

  6. LifecycleObserver ,Lifecycle 的观察者,利用它我们可以享受 Lifecycle 带来的能力;

  7. ReflectiveGenericLifecycleObserver,它存储了我们在 Observer 里注解的方法,并在生命周期发生改变的时候最终通过反射的方式调用对应的方法。

7. 总结


Lifecycle 是一个专门用来处理生命周期的库,它能够帮助我们将 Acitivity、Framgent 的生命周期处理与业务逻辑处理进行完全解耦,让我们能够更加专注于业务;通过解耦让 Activity、Fragment 的代码更加可读可维护。


可以这么说 Lifecycle 的出现彻底解决了 Android 开发遇到的生命周期处理难题,并且还给开发者带来了新的架构姿势,让我们可以设计出更加合理的架构。


妈妈再也不用担心我遇到生命周期难题了!


同时 Lifecycle 作为 AAC 的基石,为 LiveDataViewModel 的登场打下坚实的基础。


那么,LiveData、ViewModel 的背后又是什么原理呢?

尽请期待下一篇!


8. 参考与推荐

  1. https://developer.android.com/topic/libraries/architecture

  2. https://developer.android.com/topic/libraries/architecture/lifecycle


(EOF)


写这篇文章断断续续大约花了超 3 周的时间,不断地打磨,最终成文大约 4200 字,多张精心制作的图片,耗费了大量的心血,还找了内测读者帮忙审阅,就想为大家带来真正有价值的文章,如果你觉得我的付出对你来说有帮助的话,还请支持一下啦,帮忙分享一下到朋友圈,或者分享下给你的好友,帮忙传播一下。

感谢支持,谢谢,比心。


往期推荐

【AAC 系列一】Android 应用架构新时代来临!

Google I/O 2019  Android 开发者关注些什么?

这可能是一年中进阿里最好的机会了

【源码分析】Lottie 实现炫酷动画背后的原理

嗷嗷加班,如何保持学习能力~


640?wx_fmt=png

听说点“在看”的都是有前途的工程师喲

640?wx_fmt=gif


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Jetpack架构组件从入门到精通》.pdf 是一本介绍Android Jetpack架构组件的书籍。Jetpack是Google官方提供的一套组件库,旨在帮助开发者更轻松地构建高质量的Android应用程序。 这本书从入门到精通地介绍了Jetpack架构组件的各个方面。首先,它详细解释了Jetpack的基本概念和使用方法。读者可以学习到Jetpack的核心组件,如ViewModel、LiveData、Room和Navigation等,以及它们在构建Android应用时的作用。 此外,这本书还介绍了Jetpack架构组件的一些高级技术和最佳实践。读者可以学习到如何使用WorkManager实现后台任务,如何使用DataBinding进行数据绑定,以及如何使用Paging构建分页列表等。 除了介绍Jetpack架构组件的基本用法和高级技术,这本书还提供了一些实际应用示例和案例分析。读者可以通过参考这些示例来更好地理解和应用Jetpack架构组件。 总之,《Jetpack架构组件从入门到精通》.pdf 是一本全面而深入地介绍Jetpack架构组件的书籍。无论是初学者还是有一定经验的开发者,都可以通过阅读这本书来提升自己在Android应用开发中使用Jetpack的能力。 ### 回答2: 《Jetpack架构组件从入门到精通》.pdf 是一本关于Jetpack架构组件的学习指南。Jetpack是Android开发中一套强大而且灵活的组件集合,旨在帮助开发者更轻松地构建高质量的Android应用程序。 该PDF文件从入门到精通地介绍了Jetpack架构组件的各个方面。首先,它向读者介绍了Jetpack的概念和使用场景,以帮助读者了解为什么应该学习和使用这些组件。 接下来,该指南逐一介绍了Jetpack架构组件的不同模块,包括ViewModel、LiveData、Room、Navigation等。它详细解释了每个组件的功能和用法,并通过实际示例演示了如何在项目中使用它们。 此外,该指南还提供了一些常见的最佳实践和实用技巧,以帮助读者更好地理解和运用Jetpack架构组件。它还包含了一些常见问题和解决方案,帮助读者避免在实践中遇到的常见问题。 最后,该指南还提供了一些参考资料和进一步学习资源,以帮助读者深入学习和掌握Jetpack架构组件。 总的来说,该《Jetpack架构组件从入门到精通》.pdf提供了一个全面而详尽的学习指南,帮助读者了解和应用Jetpack架构组件,使他们能够更高效地构建高质量的Android应用程序。无论是初学者还是有经验的开发者,该指南都是一个值得阅读和参考的资源。 ### 回答3: 《Jetpack架构组件从入门到精通》.pdf 是一本介绍Android Jetpack架构组件的电子书,它有助于开发者学习和理解如何使用这些组件来构建高质量、稳定的Android应用程序。 Jetpack架构组件是由谷歌开发的一组库,旨在帮助开发者简化Android应用的开发过程。它提供了一系列的工具和组件,涵盖了各个方面,包括界面设计、数据库、网络通信、数据绑定、后台处理等。 这本电子书从入门到精通地介绍了各个组件的使用方法和最佳实践。它首先详细介绍了Jetpack架构组件的核心概念和优势,让读者了解为什么要使用这些组件。 然后,电子书逐一介绍了常用的Jetpack组件,如Lifecycle、ViewModel、Room、LiveData、Navigation等。每个组件都被详细地讲解,包括其作用、使用方法和示例代码。读者可以通过跟随书中的案例来实际操作和理解这些组件的使用。 除了介绍各个组件,电子书还分享了一些进阶的使用技巧和开发经验。这些技巧包括如何优化应用性能、处理异步任务、实现数据缓存等。通过这些实用的技巧,开发者可以进一步提高应用的质量和用户体验。 总的来说,《Jetpack架构组件从入门到精通》.pdf 是一本很有价值的学习资料,对于想要深入学习和掌握Jetpack架构组件的开发者来说是必不可少的参考书籍。无论是初学者还是有经验的开发者,都可以从中获得知识和技能的提升。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值