首语
3月4日,Google重磅发布了 Flutter 2 !作为 Flutter 的重大升级,使用 Flutter 2 开发者可以用相同的代码,把使用 Flutter 开发的应用发布到五个操作系统:iOS,Android,Windows,macOS 和 Linux;以及运行到 Chrome 、 Firefo, Safari 或 Edge等浏览器的 Web 版本上,Flutter 甚至还可以嵌入到 Cars, TVs 和智能家电中。 作为一个Flutter开发者,也马上下载了Flutter 2.0 sdk,并将自己的Flutter项目运行到Chrome上,效果很好,就是代码中有些差别,Web端对图片以及dart的io包不支持等等。具体差异可以去Flutter官网查看。贴一张web端效果图。
介绍
2017年Google I/O大会上,Google推出了AAC(Android Architecture Components),其中包含了LiveData、ViewModel和Room等专门为架构所设计的组件。AAC也可以被当作Jetpack的前身。在2018年Google I/O大会上,Google在AAC的基础上推出了Jetpack。
Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。 Jetpack主要包含以下四个方面,分别是架构(Architecture)、界面(UI)、行为(Behavior)和基础(Foundation)。
- Architecture组件可帮助您设计健壮,可测试和可维护的应用程序。
- Foundation组件提供了跨领域功能,例如向后兼容性,测试和Kotlin语言支持。
- Ul组件提供了小部件和帮助程序,使应用程序不仅简单易用,而且使用起来令人愉快。
- Behavior组件可帮助应用与标准的Android服务集成,例如通知,权限,共享和助手。 其中的Architecture组件是我们关注的重点。下面会对其中的组件进行展开学习。下面的这张图是Jetpack刚发布时候的图,现在Jetpack的组件已经不止图中的这些了。详细组件见Android Jetpack所有库。
优点
- 遵循最佳做法 Android Jetpack 组件采用最新的设计方法构建,具有向后兼容性,可以减少崩溃和内存泄露。
- 消除样板代码
Android Jetpack 可以管理各种繁琐的
Activity
(如后台任务、导航和生命周期管理),以便可以专注于打造出色的应用。 - 减少不一致 这些库可在各种 Android 版本和设备中以一致的方式运作,助您降低复杂性。
AndroidX 概览
AndroidX 命名空间中的工件包含 Android Jetpack库。与support库一样,AndroidX命名空间中的库与 Android 平台分开提供,并向后兼容各个 Android 版本。 如果要将项目迁移到AndroidX,在Android Studio的菜单栏中选择Refactor—>Migrate to AndroidX。完成之后,打开gradle.properties文件,可以看到这两行代码:
代码语言:javascript复制# 表示是否使用AndroidX
android.useAndroidX=true
# 表示是否将第三方库迁移到AndroidX
android.enableJetifier=true
对于新版本的Android Studio已经默认支持AndroidX了,不需要如上操作。
LifeCycle
我们经常要在页面的onCreate()
中对组件初始化,在onPause()
中停止组件,在onDestory()
中对组件进行回收。这样的工作繁琐且代码难以维护,还会引发内存泄漏。
为此,Google提供了LifeCycle作为解决方案。LifeCycle可以帮助开发者简历可感知生命周期的组件,通过使用生命周期感知型组件,您可以将依赖组件的代码从生命周期方法移入组件本身中,从而降低了模块间的耦合性和内存泄漏的可能性,编写出更精简的代码且易于维护。
LifeCycle的原理
Lifecycle 是一个类,用于存储有关组件(如 Activity
或 Fragment
)的生命周期状态的信息,并允许其他对象观察此状态。
Lifecycle 使用两种主要枚举跟踪其关联组件的生命周期状态:
- 事件(Event)
从框架和
Lifecycle
类分派的生命周期事件。这些事件映射到Activity
和Fragment
中的回调事件。
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
- 状态(state) 由 Lifecycle 对象跟踪的组件的当前状态。
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
//比较此状态是否大于或等于给定状态
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
这些我们都可以从Lifecycle类的源码中能看到,具体说明如下图所示。
Jetpack给我们提供了两个类:LifeCycleOwner
(被观察者)和LifeCycleObserver
(观察者)。通过观察者模式实现对页面生命周期的监听。
我们在ComponentActivity
的源码中可以看到它实现了LifecycleOwner
接口,接口中只有一个getLifeCycle()
,LifeCycle正是通过该方法实现观察者模式,源码中已经实现了被观察者实现的那部分。
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
我们监听 Atctivity
的生命周期时,只需要实现观察者那一部分的代码,即让自定义组件实现LifecycleObserver
接口即可。
public class MyObserver implements LifecycleObserver {
//当Activity执行onResume()时,该自动调用
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
...
}
}
在Activity
中,只需要使用以下代码,将观察者和被观察者绑定起来,不用再担心Activity
生命周期变化对组件带来的影响。
getLifecycle().addObserver(new MyObserver());
LifecycleService
Android中除了Activity
和Fragment
有生命周期外,还有一个重要的组件Service
,为了方便对Service
生命周期的监听,Android提供了LifecycleService
类,该类继承于Service
,并实现了LifecycleOwner
接口。和Activity
和Fragment
类似,也有一个getLifecycle()
供我们调用,部分源码如下。
public class LifecycleService extends Service implements LifecycleOwner {
private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
@Override
@NonNull
public Lifecycle getLifecycle() {
return mDispatcher.getLifecycle();
}
}
使用LifecycleService
时,我们需要添加如下依赖:
implementation "androidx.lifecycle:lifecycle-service:2.3.0"
使用和Activity
中的类似,在Service
中绑定观察者,在自定义Observer
中实现事件的绑定。使用LifecycleService
很好的实现了组件与Service
之间的解耦,在其内部自行管理生命周期带来的变化。
ProcessLifecycleOwner
具有生命周期的组件除了Activity
、Fragment
和Service
,还有Application
。很多时候我们想知道应用程序处于前台还是后台,或者后台回到前台可以得到通知。为此,LifeCycle提供了一个ProcessLifecycleOwner
类,方便我们知道整个应用程序的生命周期情况。
使用ProcessLifecycleOwner
时,我们需要添加如下依赖:
implementation "androidx.lifecycle:lifecycle-process:2.3.0"
ProcessLifecycleOwner
的使用方式和Activity
、Fragment
和Service
类似,其本质都是观察者模式,在Application
中绑定观察者,在自定义Observer
中绑定事件。
有了ProcessLifecycleOwner
,我们可以方便获取到应用生命周期的变化,在其中做一些业务操作,减少了项目代码的耦合性。但需要注意的是:
ProcessLifecyoleowner
是针对整个应用程序的监听,与Activity
数量无关。Lifecycle.Event.ON CREATE
只会被调用一次,而Lifecycle.Event.ON_DESTROY
永远不会被调用。- 当应用程序从后台回到前台,或者应用程序被首次打开时,会依次调用
Lifecycle.Event.ON_START
和Lifecycle.Event.ON_RESUME
。 - 当应用程序从前台退到后台(用户按下 Home 键或任务菜单键),会依次调用
Lifecycle.Event.ON PAUSE
和Lifecycle.Event.ON_ STOP
。
ON_STOP 事件
如果 Lifecycle
属于AppCompatActivity
或Fragment
,那么调用 AppCompatActivity
或Fragment
的onSaveInstanceState()
时,Lifecycle
的状态会更改为 CREATED
并且会分派ON_STOP
事件。在FragmentActivity
的源码中可以看到。
markFragmentsCreated();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
private void markFragmentsCreated() {
boolean reiterate;
do {
reiterate = markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
} while (reiterate);
}
private static boolean markState(FragmentManager manager, Lifecycle.State state) {
boolean hadNotMarked = false;
Collection<Fragment> fragments = manager.getFragments();
for (Fragment fragment : fragments) {
if (fragment == null) {
continue;
}
if (fragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
fragment.mLifecycleRegistry.setCurrentState(state);
hadNotMarked = true;
}
if (fragment.getHost() != null) {
FragmentManager childFragmentManager = fragment.getChildFragmentManager();
hadNotMarked |= markState(childFragmentManager, state);
}
}
return hadNotMarked;
}
通过onSaveInstanceState()
保存 Fragment 或AppCompatActivity
的状态后,其界面被视为不可变,直到调用ON_START
。如果在保存状态后尝试修改界面,很可能会导致应用的导航状态不一致,因此应用在保存状态后运行 FragmentTransaction
时,FragmentManager
会抛出异常。
AppCompatActivity
的onStop()
会在onSaveInstanceState()
之后调用,这样就会留下一个缺口,即不允许界面状态发生变化,但 Lifecycle
尚未移至 CREATED
状态。
为防止出现这个问题,beta2 及更低版本中的 Lifecycle
类会将状态标记为CREATED
而不分派事件,这样一来,即使未分派事件(直到系统调用onStop()
),检查当前状态的代码也会获得实际值。
用例
- 位置更新之间切换。
- 开始和停止视频缓冲。
- 开始和停止网络连接。
- 暂停和恢复动画可绘制资源。