本篇文章向您介绍了用于构建Android应用程序的如下生命周期感知架构组件:html
在此代码框中,您能够实现上述每一个组件的示例。首先是示例应用程序,而后经过一系列步骤添加代码,在进度时集成各类体系结构组件。java
下载代码android
git clone git@github.com:googlecodelabs / android-lifecycles.git
复制代码
运行程序:git
旋转屏幕,注意计时器重置github
若是咱们按照以前的逻辑须要保存状态,而后恢复状态,并恢复计时器。如今您能够用ViewModel,由于由于此类的实例在配置更改后仍然存在,例如屏幕旋转。shell
在此步骤中,您使用ViewModel来跨屏幕旋转保持状态并解决您在上一步中观察到的行为。在上一步中,您运行了一个显示计时器的活动。当配置更改(例如屏幕旋转)破坏活动时,将重置此计时器。缓存
可使用ViewModel在活动或片断的整个生命周期中保留数据。如前一步所示,活动是管理应用数据的不良选择。活动和片断是短暂的对象,当用户与应用程序交互时,这些对象会频繁建立和销毁。 ViewModel还更适合管理与网络通讯相关的任务,以及数据操做和持久性。bash
打开ChronoActivity2并检查类如何检索和使用ViewModel:网络
ChronometerViewModel chronometerViewModel
= ViewModelProviders.of(this).get(ChronometerViewModel.class);
复制代码
this指的是一个实例LifecycleOwner。ViewModel只要活动范围存在,框架就会保持LifecycleOwner活力。ViewModel若是其全部者因配置更改(例如屏幕旋转)而被销毁,则不会销毁A. 全部者的新实例从新链接到现有实例,ViewModel以下图所示:架构
Activity或Fragment的范围从建立到完成(或终止),您不得与销毁混淆。请记住,当旋转设备时,活动会被销毁,但ViewModel与之关联的任何实例都不会被销毁。
运行应用程序(在“运行配置”下拉列表中选择“ 步骤2 ”),并在执行如下任一操做时确认计时器未重置:
可是,若是您或系统退出应用程序,则计时器将重置。
系统会ViewModel在生命周期全部者的整个生命周期中保留内存中的实例,例如片断或活动。系统不会持久ViewModel存储长期存储。
在此步骤中,您将使用a的自定义计时器替换前面步骤中使用的计时器Timer,并每秒更新UI。 Timer是一个java.util可用于在未来循环安排任务的类。您将此逻辑添加到LiveDataTimerViewModel类中,并使活动专一于管理用户和UI之间的交互。
当计时器通知时,活动会更新UI。为了不内存泄漏,ViewModel不包括对活动的引用。例如,配置更改(例如屏幕旋转)可能会致使对ViewModel应该进行垃圾回收的活动的引用。系统将保留实例,ViewModel直到相应的活动或生命周期全部者再也不存在。
注意:存储到一个参考上下文或视图中ViewModel可能会致使内存泄漏。避免使用引用Context或View类实例的字段。所述onCleared()方法是用于清除引用有用退订或明确的引用与长周期其它的目的,但不Context或View对象。
ViewModel您能够将活动或片断配置为观察数据源,而不是直接从其中修改视图,并在数据更改时接收数据。这种安排称为观察者模式。
注意:要将数据公开为可观察对象,请将类型包装在LiveData类中。
若是您使用了数据绑定库或其余反应库(如RxJava),您可能熟悉观察者模式。LiveData是一个特殊的可观察类,它是生命周期感知的,只通知活跃的观察者。
ChronoActivity3是一个实例LifecycleActivity,它能够提供生命周期的状态。这是类声明:
public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner {...}
复制代码
将LifecycleRegistryOwner用于的实例的生命周期结合ViewModel并LiveData与活动或片断。片断的等价类是LifecycleFragment。
1.将如下代码添加到方法中的ChronoActivity3类中subscribe()以建立订阅:
mLiveDataTimerViewModel.getElapsedTime().observe(this, elapsedTimeObserver);
复制代码
2.接下来,在LiveDataTimerViewModel类中设置新的通过时间值。找到如下注释
//TODO set the new value
复制代码
用如下语句替换注释:
mElapsedTime.postValue(newValue);
复制代码
3.运行应用程序并在Android Studio中打开Android Monitor。请注意,除非您导航到另外一个应用程序,不然日志会每秒更新。若是您的设备支持多窗口模式,您可能想尝试使用它。旋转屏幕不会影响应用的行为方式。
注意:LiveData对象仅在活动时发送更新,或者处于LifecycleOwner活动状态。若是您导航到其余应用程序,日志消息会暂停,直到您返回。LiveData对象仅在其各自的生命周期全部者为STARTED或时将订阅视为活动的RESUMED。
许多Android组件和库要求您:
未能完成上述步骤可能会致使内存泄漏和细微错误。
能够将生命周期全部者对象传递给生命周期感知组件的新实例,以确保它们了解生命周期的当前状态。
您可使用如下语句查询生命周期的当前状态:
lifecycleOwner.getLifecycle().getCurrentState()
复制代码
上面的语句返回一个状态,例如Lifecycle.State.RESUMED,或Lifecycle.State.DESTROYED。
实现的生命周期感知对象LifecycleObserver还能够观察生命周期全部者状态的变化:
lifecycleOwner.getLifecycle().addObserver(this);
复制代码
您能够注释对象以指示它在须要时调用适当的方法:
@OnLifecycleEvent(Lifecycle.EVENT.ON_RESUME)
void addLocationListener() { ... }
复制代码
在此步骤中,您将建立一个对活动生命周期全部者做出反应的组件。使用片断做为生命周期全部者时,相似的原则和步骤适用。
您使用Android框架LocationManager获取当前的纬度和经度并将其显示给用户。此添加容许您:
您一般会订阅活动或方法中的LocationManager更改,并删除或方法中的侦听器:onStart() onResume() onStop() onPause()
// Typical use, within an activity.
@Override
protected void onResume() {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mListener);
}
@Override
protected void onPause() {
mLocationManager.removeUpdates(mListener);
}
复制代码
在此步骤中,您将在LifecycleOwner名为LifecycleRegistryOwner的类中使用被调用的实现BoundLocationManager。BoundLocationManager类的名称指的是类的实例绑定到活动的生命周期。
要让类观察活动的生命周期,必须将其添加为观察者。要实现此BoundLocationManager目的,请经过将如下代码添加到其构造函数来指示对象观察生命周期:
lifecycleOwner.getLifecycle().addObserver(this);
复制代码
要在发生生命周期更改时调用方法,可使用@OnLifecycleEvent注释。使用类中的如下注释更新addLocationListener()和removeLocationListener()方法BoundLocationListener:
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void addLocationListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void removeLocationListener() {
...
}
复制代码
注意:观察者被带到提供者的当前状态,所以不须要addLocationListener()从构造函数调用。当观察者被添加到生命周期全部者时,它会被调用。
旋转设备时,运行应用程序并验证日志监视器是否显示如下操做:
D / BoundLocationMgr:添加了监听器
D / BoundLocationMgr:已删除侦听器
D / BoundLocationMgr:添加了监听器
D / BoundLocationMgr:已删除侦听器
复制代码
使用Android模拟器模拟更改设备的位置(单击三个点以显示扩展控件)。在TextView当它改变时被更新:
使用ViewModel完成如下附加步骤在Fragment之间的通讯:
运行此步骤并注意其中两个实例SeekBar彼此独立:
使用ViewModel以便在SeekBar更改Fragment时SeekBar更新另外一个Fragment:
注意:您应该将活动用做生命周期全部者,由于每一个Fragment的生命周期是独立的。
本节中使用的模块处于alpha阶段。这意味着API不是最终的,未来可能会发生变化。
从内存管理概述:
当用户在应用程序之间切换时,Android会保留非前景的应用程序 - 即用户不可见或在最近最少使用(LRU)缓存中运行音乐播放等前台服务。例如,当用户首次启动应用程序时,会为其建立一个进程; 可是当用户离开应用程序时,该进程不会退出。系统会保持进程缓存。若是用户稍后返回应用程序,系统将从新使用该过程,从而使应用程序切换更快。
因为系统内存不足,它会从最近最少使用的进程开始杀死缓存中的进程。当用户导航回应用程序时,系统将在新进程中从新启动应用程序。
因为只有在用户暂时没有与应用程序交互时才会发生这种状况,所以可能容许他们返回应用程序并在初始状态下找到它。可是,在某些状况下,您可能但愿保存应用程序的状态或部分应用程序的状态,以便在进程被杀死时不会丢失该信息。
该 lifecycle-viewmodel-savedstate模块提供对ViewModel中已保存状态的访问。
该模块的gradle依赖是
"androidx.lifecycle:lifecycle-viewmodel-savedstate:$savedStateVersion"
复制代码
ViewModels须要两次更改才能访问已保存的状态:
首先,让咱们在没有这些变化的状况下尝试第6步:
1.打开运行配置“步骤6”
你会看到一个简单的表单:
2.更更名称,而后单击“保存”。这将把它存储在ViewModel内的LiveData中。
3.模拟系统终止进程(须要运行P +的仿真器)。首先输入如下命令确保进程正在运行:
$ adb shell ps -A | grep lifecycle
复制代码
这应该输出带有名称的运行进程 com.example.android.codelabs.lifecycle
在设备或模拟器上按Home,而后运行
$ adb shell am kill com.example.android.codelabs.lifecycle
复制代码
若是你再输入一次
$ adb shell ps -A | grep lifecycle
复制代码
你应该什么也得不到,代表这个过程已被正确杀死。
4.再次打开应用程序(在应用程序启动器中查找LC Step6)。
ViewModel中的值未保留,但已EditText恢复其状态。这怎么可能?
一些UI元素,包括EditText使用本身的onSaveInstanceState实现保存其状态。在进程被终止后,此状态将在配置更改后恢复时恢复。阅读ViewModels:Persistence,onSaveInstanceState(),恢复UI状态和加载器以获取更多信息。
实际上,该lifecycle-viewmodel-savedstate模块还使用onSaveInstanceState和onRestoreInstanceState保持ViewModel状态,但它使这些操做更方便。
为ViewModel实现保存的状态 在SavedStateActivity.java文件中,替换
mSavedStateViewModel = ViewModelProviders.of(this).get(SavedStateViewModel.class);
复制代码
为:
mSavedStateViewModel = ViewModelProviders.of(this, new SavedStateVMFactory(this))
.get(SavedStateViewModel.class);
复制代码
在SavedStateViewModel.java文件中,您须要添加一个新的构造函数,该构造函数SavedStateHandle将状态存储在私有字段中:
private SavedStateHandle mState;
public SavedStateViewModel(SavedStateHandle savedStateHandle){
mState = savedStateHandle;
}
复制代码
如今您将使用该模块的LiveData支持,所以您再也不须要存储它:
private static final String NAME_KEY =“name”;
//公开不可变的LiveData
LiveData <String> getName(){
return mState.getLiveData(NAME_KEY);
}
void saveNewName(String newName){
mState.set(NAME_KEY,newName);
}
复制代码
如今您正在使用LiveData mState,MutableLiveData名称再也不使用,能够删除。
如今您能够再次尝试相同的过程。打开应用程序,更更名称并保存。而后,按Home并使用如下命令终止该过程:
$ adb shell am kill com.example.android.codelabs.lifecycle
复制代码
若是您从新打开该应用程序,您将看到ViewModel中的状态此时已保存。