背景
Android Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。也就是说,Google 开发了一套通用的库让我们使用,帮助开发者高效的开发应用的工具集。详细内容可以参考这里。
介绍
Lifecycle 是 Android Jetpack 的一部分,是生命周期感知型组件,可执行操作来响应另一个组件(Activity 和 Fragment)的生命周期状态的变化。Lifecycle 是一个类,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态。它是 LiveData 和 ViewModel 的基础,如果你想更深入的了解 Android Jetpack 的其他组件,你应该从它学起。
为什么我们需要它?
举个例子,假设我们有一个在屏幕上显示设备位置的 Activity。常见的实现可能如下所示:
internal class MyLocationListener(
private val context: Context,
private val callback: (Location) -> Unit
) {
fun start() {
// connect to system location service
}
fun stop() {
// disconnect from system location service
}
}
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
myLocationListener.start()
// manage other components that need to respond
// to the activity lifecycle
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
// manage other components that need to respond
// to the activity lifecycle
}
}
虽然这个例子看起来没有太大的问题,但是在实际应用中,最终会有太多管理界面和其他组件的调用,以响应生命周期的当前状态。比如多个组件会在生命周期方法(onStart()
和 onStop()
)中放置大量代码,不利于维护。
此外,无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 onStart()
中的某种配置检查)时尤其如此。这可能会导致出现一种竞态条件,在这种条件下,onStop()
方法会在 onStart()
之前结束,这使得组件留存的时间比所需的时间要长。
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
Util.checkUserStatus { result ->
// 如果在 activity stop 后调用此回调该怎么办?,通常我们的处理是注销回调,要手动处理,使用 Lifecycle 就自动帮助我们处理了。
if (result) {
myLocationListener.start()
}
}
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
}
}
androidx.lifecycle
软件包提供的类和接口可帮助您以弹性和隔离的方式解决这些问题。
基础使用
导入依赖
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
Lifecycle 使用
然后我们来看看怎么解决上面的问题?我们可以通过添加注解来监控组件的生命周期状态,您可以通过调用 Lifecycle
类的 addObserver()
方法并传递观察者的实例来添加观察者,如以下示例中所示:
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener() {
...
}
}
myLifecycleOwner.getLifecycle().addObserver(MyObserver())
LifecycleOwner
是单一方法接口,表示类具有 Lifecycle
。它具有一种方法(即 getLifecycle()
,该方法必须由类实现。此接口从各个类(如 Fragment
和 AppCompatActivity
)抽象化 Lifecycle 的所有权,并允许编写与这些类搭配使用的组件。任何自定义应用类均可实现 LifecycleOwner 接口。
实现 LifecycleObserver 的组件可与实现 LifecycleOwner 的组件完美配合,因为所有者可以提供生命周期,而观察者可以注册以观察生命周期。
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this, lifecycle) { location ->
// update UI
}
Util.checkUserStatus { result ->
if (result) {
myLocationListener.enable()
}
}
}
}
对于未知跟踪实例,我们可以让MyLocationListener
类实现 LifecycleObserver
,然后在 onCreate
方法中实现 Activity 的 Lifecycle 对其进行初始化,然后配合注解。这意味着对生命周期状态的变化做出响应的逻辑会在MyLocationListener
(而不是在 Activity)中进行声明。让各个组件存储自己的逻辑可使 Activity 和 Fragment 逻辑更易于管理。
同时还要注意的是,如果 Lifecycle
现在未处于良好的状态,则应避免调用某些回调。例如,如果回调在 Activity 状态保存后运行 Fragment 事务,就会触发崩溃,因此我们绝不能调用该回调。为简化此使用场景,Lifecycle 类允许其他对象查询当前状态。
对应到 MyLocationListener 的做法如下:
internal class MyLocationListener(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
): LifecycleObserver {
private var enabled = false
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun start() {
if (enabled) {
// connect
}
}
fun enable() {
enabled = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// connect if not connected
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stop() {
// disconnect if connected
}
}
对于此实现,LocationListener
类可以完全感知生命周期。如果我们需要从另一个 Activity 或 Fragment 使用 LocationListener
,只需对其进行初始化。所有设置和拆解操作都由类本身管理。
如果您尝试管理整个应用进程的生命周期,请参阅 ProcessLifecycleOwner。
Applicaiton 生命周期 ProcessLifecycleOwner
通常我们判断在应用是不是处于前后台的做法是:注册一个 registerActivityLifecycleCallbacks(callback),然后在 callback 中利用一个全局变量做计数,在onActivityStarted()中计数加1,在onActivityStopped方法中计数减1,从而判断前后台切换。
而使用ProcessLifecycleOwner可以直接获取应用前后台切换状态(记得先引入lifecycle-process依赖)。使用方式和Activity 中类似,只不过要使用 ProcessLifecycleOwner.get()
获取 ProcessLifecycleOwner,代码如下:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//注册App生命周期观察者
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationLifecycleObserver());
}
/**
* Application生命周期观察,提供整个应用进程的生命周期
*
* Lifecycle.Event.ON_CREATE只会分发一次,Lifecycle.Event.ON_DESTROY不会被分发。
*
* 第一个Activity进入时,ProcessLifecycleOwner将分派Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME。
* 而Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP,将在最后一个Activit退出后后延迟分发。如果由于配置更改而销毁并重新创建活动,则此延迟足以保证ProcessLifecycleOwner不会发送任何事件。
*
* 作用:监听应用程序进入前台或后台
*/
private static class ApplicationLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForeground() {
Log.w(TAG, "ApplicationObserver: app moved to foreground");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackground() {
Log.w(TAG, "ApplicationObserver: app moved to background");
}
}
}
实现自定义 LifecycleOwner
支持库 26.1.0 及更高版本中的 Fragment 和 Activity 已实现 LifecycleOwner
接口。如果你有一个自定义类并希望使其成为 LifecycleOwner
,可以使用 LifecycleRegistry
类,但需要将事件转发到该类,代码如下:
class MyActivity : Activity(), LifecycleOwner {
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
public override fun onStart() {
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
}
该 MainActivty 是实现了 Activity 类,而不是 AppcompatActivity(FragmentActivity) 类,所以需要这样的处理。我们来看看 FragmentActivity 中的源码,比如 onCreate
方法和 onPause
方法
public class FragmentActivity extends ComponentActivity implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
/**
* A {@link Lifecycle} that is exactly nested outside of when the FragmentController
* has its state changed, providing the proper nesting of Lifecycle callbacks
*
* TODO(b/127528777) Drive Fragment Lifecycle with LifecycleObserver
*/
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
protected void onCreate(@Nullable Bundle savedInstanceState) {
···
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
···
}
@Override
protected void onPause() {
super.onPause();
···
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
}
//ComponentActivity.java
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
明白了基本的操作,我们再看看看源码是如何实现的,注意,本文不会仔细深究源码,而是梳理一个大概的思路,如果想要讲具体深入每个细节,则可以照着我这个思路深入研究。
源码分析
Lifecycle 五种状态对应六个事件(生命周期)
首先我们来看 Lifecycle 这个类,让脑子里面有一个大致的概念
public abstract class Lifecycle {
/**
* Lifecycle coroutines extensions stashes the CoroutineScope into this field.
*
* @hide used by lifecycle-common-ktx
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
AtomicReference
如果你觉得还不够清楚,只需要要记住五种状态对应六个生命周期方法(六个事件,ON_ANY 可以忽略)。然后我们再来看看官方的图,五个状态对应六个生命周期方法,六个事件,这句话一定要记住。
Event 表示生命周期事件,与 Activity/Fragment 生命周期方法对应。State 是 Lifecycle 这些生命周期对应的状态,为什么不直接用对应的生命周期设置对应的状态呢,而是设置了五个状态呢?原因很简单,因为 Lifecycle 不仅仅只是给自己用这些状态,还有 LiveData,ViewMode 等控件也会用到这些状态的进行逻辑判断,所以 Google 工程师做了更好的封装和管理。
//Lifecycle.class
* {@link Event#ON_CREATE}, {@link Event#ON_START}, {@link Event#ON_RESUME} events in this class
* are dispatched after the {@link LifecycleOwner}'s related method returns.
* {@link Event#ON_PAUSE}, {@link Event#ON_STOP}, {@link Event#ON_DESTROY} events in this class
* are dispatched before the {@link LifecycleOwner}'s related method is called.
Event 中的 ON_CREATE,ON_START,ON_RESUME 是在 LifecyclerOwner 对应的方法执行之后分发,ON_PAUSE,ON_STOP,ON_DESTROY 是在 LifecyclerOwner 对应的方法执行之前分发。
我们的 Activity 因为实现了 LifecycleOwner 才能直接调用 getLifecycle()
,从前面的分析我们可以看到是在 ComponentActivity 中实现了该接口
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSavedStateRegistryController.performRestore(savedInstanceState);
ReportFragment.injectIfNeededIn(this);
if (mContentLayoutId != 0) {
setContentView(mContentLayoutId);
}
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
// LifecycleRegistry.java
public class LifecycleRegistry extends Lifecycle {
getLifecycle().addObserver(MyObserver())
是我们添加观察者的方式,我们来看看addObserver
方法的实现,因为的实现是LifecycleRegistry
//LifecycleRegistry.java
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
//带状态的观察者,这个状态的作用:新的事件触发后 遍历通知所有观察者时,判断是否已经通知这个观察者了
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
//下面代码的逻辑:通过while循环,把新的观察者的状态 连续地 同步到最新状态mState。
//意思就是:虽然可能添加的晚,但把之前的事件一个个分发给你(upEvent方法),即粘性
boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
while ((statefulObserver.mState.compareTo(targetState)
通过statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
分发事件,我们先来看ObserverWithState
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 = getStateAfter(event);
mState = min(mState, newState);
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
mLifecycleObserver
的值为Lifecycling.lifecycleEventObserver(observer);
,然后查看方法lifecycleEventObserver
@NonNull
static LifecycleEventObserver lifecycleEventObserver(Object object) {
boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
···
return new ReflectiveGenericLifecycleObserver(object);
}
查看最后一行中的ReflectiveGenericLifecycleObserver
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(LifecycleOwner source, Event event) {
mInfo.invokeCallbacks(source, event, mWrapped); //执行状态变化对应的方法
}
}
getInfo
的内容如下:
CallbackInfo getInfo(Class klass) {
CallbackInfo existing = mCallbackMap.get(klass);
if (existing != null) {
return existing;
}
existing = createInfo(klass, null);
return existing;
}
处理注解
接下来是重要方法createInfo
,在该方法中进行注解的处理,并存储到 mCallbackMap。提供给后面的观察者调用
//createInfo,遍历方法 处理注解,将
private CallbackInfo createInfo(Class klass, @Nullable Method[] declaredMethods) {
Class superclass = klass.getSuperclass();
Map handlerToEvent = new HashMap();
if (superclass != null) {
CallbackInfo superInfo = getInfo(superclass);
if (superInfo != null) {
handlerToEvent.putAll(superInfo.mHandlerToEvent);
}
}
Class[] interfaces = klass.getInterfaces();
for (Class intrfc : interfaces) {
for (Map.Entry entry : getInfo(
intrfc).mHandlerToEvent.entrySet()) {
verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass);
}
}
Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);
boolean hasLifecycleMethods = false;
for (Method method : methods) {
OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
if (annotation == null) {
continue;
}
hasLifecycleMethods = true;
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");
}
}
Lifecycle.Event event = annotation.value();
···
MethodReference methodReference = new MethodReference(callType, method);
verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
}
CallbackInfo info = new CallbackInfo(handlerToEvent);
mCallbackMap.put(klass, info);
mHasLifecycleMethods.put(klass, hasLifecycleMethods);
return info;
}
被观察者通知观察者
观察者进行回调的时候调用了ReflectiveGenericLifecycleObserver
的mInfo.invokeCallbacks(source, event, mWrapped);
,最终会调用到MethodReference
的invokeCallback
方法。
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);
}
}
到这里观察者的注册和注解的处理,以及通知被观察者的流程就已经分析完毕了。
如何监听生命周期
我们回到之前的ComponentActivity
的onCreate
方法中可以看到调用了ReportFragment.injectIfNeededIn(this);
,这个 ReportFragment 和 Glide 中使用透明的 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();
}
}
然后通过dispatch
方法分发生命周期
@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
的具体逻辑如下,最终都是调用 handleLifecycleEvent
来处理
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);
}
}
}
因为我们这里是LifecycleRegistryOwner
,所以来看看其handleLifecycleEvent
方法
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
紧接着调用moveToState
方法
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;
}
接着调用sync
方法,然后把生命周期同步给所有观察者
// 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) newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
最终是调用了forwardPass
方法,然后调用了ObserverWithState#dispatchEvent
方法,然后调用onStateChanged
方法,后面的流程就和上面一样了,整个流程就结束了。
流程图
整个流程还是比较简单的,如图所示
处理 ON_STOP 事件
由于Android 系统版本的差异,所以在依赖版本时需要注意,可以参考官方的解释。
总结
本文先从 Lifecycle 的使用,再到源码分析,分析了观察者和被观察者的注册和通知流程,也分析了生命周期的监听的使用方式,最后给出整体流程图。喜欢的点个赞吧~
文末
Jetpack Compose是谷歌在2019Google i/o大会上发布的新的库,是用于构建原生Android UI的现代工具包。他有强大的工具和直观的Kotlin API,简化并加速了Android上的UI开发。可以帮助开发者用更少更直观的代码创建View,还有更强大的功能,以及还能提高开发速度。
客观地讲,Compose 确实是一套比较难学的东西,因为它毕竟太新也太大了,它是一个完整的、全新的框架,确实让很多人感觉「学不动」,这也是个事实。
如果你是因为缺少学习资料,而我正好薅到这本谷歌内部大佬根据实战编写的《Jetpack Compose最全上手指南》,从入门到精通,教程通俗易懂,实例丰富,既有基础知识,也有进阶技能,能够帮助读者快速入门,是你学习Jetpack Compose的葵花宝典,快收藏起来!!!
第一章 初识 Jetpack Compose
1. 为什么我们需要一个新的UI 工具?
2. Jetpack Compose的着重点
- 加速开发
- 强大的UI工具
- 直观的Kotlin API
3. API 设计
4. Compose API 的原则
- 一切都是函数
- 顶层函数(Top-level function)
- 组合优于继承
- 信任单一来源
5. 深入了解Compose
- Core
- Foundation
- Material
- 插槽API
第二章 Jetpack Compose构建Android UI
1. Android Jetpack Compose 最全上手指南
- Jetpack Compose 环境准备和Hello World
- 布局
- 使用Material design 设计
- Compose 布局实时预览
……
2. 深入详解 Jetpack Compose | 优化 UI 构建
- Compose 所解决的问题
- Composable 函数剖析
- 声明式 UI
- 组合 vs 继承
- 封装
- 重组
……
3. 深入详解 Jetpack Compose | 实现原理
- @Composable 注解意味着什么?
- 执行模式
- Positional Memoization (位置记忆化)
- 存储参数
- 重组
……
第三章 Jetpack Compose 项目实战演练(附Demo)
1. Jetpack Compose应用1
- 开始前的准备
- 创建DEMO
- 遇到的问题
2. Jetpack Compose应用2
3. Jetpack Compose应用做一个倒计时器
- 数据结构
- 倒计时功能
- 状态模式
- Compose 布局
- 绘制时钟
4. 用Jetpack Compose写一个玩安卓App
- 准备工作
- 引入依赖
- 新建 Activity
- 创建 Compose
- PlayTheme
- 画页面
- 底部导航栏
- 管理状态
- 添加页面
5. 用Compose Android 写一个天气应用
- 开篇
- 画页面
- 画背景
- 画内容
……
6. 用Compose快速打造一个“电影App”
- 成品
- 实现方案
- 实战
- 不足
……
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 如何从Ubuntu Linux中删除Firefox Snap?
Ubuntu Linux是一款广受欢迎的开源操作系统,拥有强大的功能和广泛的应用程序选择。默认情况下,Ubuntu提供了一种称为Snap的软件打包格式,用于安装和管理应用程序。Firefox是一款流行的开源网络浏览器,而Firefox Snap是Firefox…