Android Jetpack介绍
Android Jetpack 是一套组件、工具和指导,可以帮助您快速构建出色的 Android 应用。
Google在17年的I/O大会上推出了架构组件(Architecture Component)工具集。
随后在18年I/O大会上发布了 Android Jetpack,Jetpack 是Android开发组件工具集,旨在帮助我们轻松构建更稳定、更健壮、以及更可维护的应用程序。
每个 Jetpack 组件均可单独采用,并且它们依然可以流畅地协作。
Jetpack主要分为4个部分,基础、架构、行为、界面。从图中得知,Jetpack并不全是些新东西,只要是能够帮助开发者更好更方便地构建应用程序的组件,Google都将其归纳入了Jetpack,可以看出Google对jetpack很重视,对开发者很上心。
紧接着Google推出AndroidX,将许多Google认为是正确的方案和实践集中起来。
- AndroidX 是对support library的重大改进。
- AndroidX中的所有软件包名都以字符串androidx.开头,位于一致的命名空间中。
- 与support支持库不同,AndroidX软件包可单独维护和更新。
- 所有新的支持库开发都将在AndroidX库中进行。
官方推荐架构
使用此架构能带来什么好处?
UI和业务逻辑解耦。
有效避免生命周期组件内存泄漏。
- 提高模块可测试性。
- 提高应用稳定性,有效降低以下异常发生概率。
- Can not perform this action after onSaveInstanceState
- WindowManager$BadTokenException, is your activity running?
- OOM 、 NullPointerException
- …
测试每个组件
界面和交互:使用 Android 界面插桩测试。基于此架构只需mock 一个
ViewModel
即可完成界面测试。ViewModel:使用 JUnit 测试。只需mock一个类,即
Repository
。Repository:使用 JUnit 测试。只需mock两个类,XxxDao,XxxService;由于XxxDao,XxxService都是接口,还可以创建虚拟实现来完成复杂测试用例。
XxxDao:可以使用插桩测试来测试 DAO 类。这里注意对于每个测试,都请创建内存中数据库以确保测试没有任何副作用(例如更改磁盘上的数据库文件)。
XxxService:就Retrofit而言可以使用MockWebServer模拟本地服务器。
Lifecycle
Lifecycle是一个类,它包含组件(Activity或Fragment)生命周期状态的信息,并允许其他对象观察此状态。
跟踪组件生命周期
- Lifecycle内部使用两个主要枚举(Event、State)来跟踪其关联组件的生命周期状态。
- Event:对应Activity或Fragment组件的生命周期回调事件。
- State:表示被跟踪组件的当前状态,其中
STARTED
和RESUMED
为活跃状态,可接受到liveData的数据更新。
LifecycleOwner和LifecycleRegistry
- LifecycleOwner : 是一个单一的方法接口,表示该类具有生命周期。support包从26.1.0版本开始,Fragment和Activity就默认实现了该接口。
- LifecycleRegistry : Lifecycle接口的实现类,协助组件处理生命周期,可处理多个观察者。如果你想自定义LifecyclerOwner请参考support包中Fragment和Activity实现。
ViewModel
ViewModel 是用来保存应用UI数据的类,它会在配置变更(Configuration Change)后继续存在。
生命周期
关于ViewModel的生命周期就一句话:在Activity/Fragment等组件整个生命周期过程中,ViewModel的实例有且只有一个。
这样设计好处在哪呢?
- 可用ViewModel存储数据,它能安全度过手机旋转等配置变更场景。
- ViewModel能很好的实现多个Fragment之间的数据共享。
单一责任原则
上图为官方中文视频截图。
- Actvity或Fragment只显示UI和接收互动。
- 为避免ViewModel臃肿,可创建presenter处理UI数据。(比如从数据列表中获取某个item的属性)
- Repository 数据源操作入口。(便于单元测试)
- 配合其它架构组件使用。
最佳实践
- 如何时候都不要将Context传入ViewModel。
- 如果要在ViewModel中使用Application实例,请使用AndroidViewModel子类。
- ViewModel+LiveData+Databinding 可构建反应式UI。(请查看文末提供的参考资料)
ViewModel与onSaveInstanceState要配合使用。
ViewModel | onSaveInstanceState
—|—
能度过配置变更 | 能度过配置变更和进程关闭
存储大量数据 | 存储少量数据| 可序列化
ViewModel和onSaveInstanceState是相辅相成的,当进程被关闭时,ViewModel会被销毁,而onSaveInstanceState不会受影响。所以用onSaveInstanceState存储少量关键数据(如xxxId),并在该场景恢复后用来加载页面数据。
ViewModel和View之间通信
- UserProfileActivity引用UserViewModel,可观察其提供的UserLiveData、StatusLiveData、PageStateLiveData数据源变更来刷新UI。
- 响应用户事件,比如更新用户信息。Activity将更新事件传递给ViewModel,ViewModel有将其委托给Presenter处理,Presenter处理过程及结果通过LiveData与Activity交互。
- 注意Activity和ViewModel之间是单向引用。为避免内存泄漏,ViewModel不能持有任何Context引用。
LiveData
LiveData是一个具有生命周期感知特性的可观察的数据保持类。
- LiveData只通知活跃状态(
STARTED
orRESUMED
)的Observer更新,并在DESTROYED
状态时自动移除Observer,避免内存泄漏。 - 始终保持最新数据。举例:1.退后台的Activity在返回前台后会立即收到最新数据。2. 配置变更导致Activity重建后也会立即收到最新数据。
- 共享资源。单利模式共享同一个LiveData。
LiveData、MutableLiveData、MediatorLiveData区别?
- 继承关系:MediatorLiveData -> MutableLiveData -> LiveData。 所以MediatorLiveData功能最强大。
- LiveData 是一个具有生命周期感知的可观察的数据保持类。
- MutableLiveData 在LiveData基础上打开了修改Value的方法权限。
- MediatorLiveData 可管理多个LiveData。
Transformations
map : 将一种数据类型的
转换为另一种类型 ```LiveData``` 1// 观察将被转换LiveData
,待其数据源变更后转换为LiveData并通知订阅者。
// 内部使用的MediatorLiveData实现。
LiveDatauserLiveData = …; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName
});
12- **switchMap** : 和map类似。差别在于triggerLiveData变更后,会触发和等待另外一个LiveData获取数据。// 实例代码:将addressInputLiveData转换为postalCodeLiveData.
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
private final MutableLiveDataaddressInput = new MutableLiveData();
public final LiveDatapostalCode = Transformations.switchMap(addressInput, (address) -> { return repository.getPostCode(address); }); public MyViewModel(PostalCodeRepository repository) { this.repository = repository }
// addressInputLiveData变更时触发repository.getPostCode,
// 待其回去成功后,再将数据设置给postalCodeLiveData。private void setInput(String address) { addressInput.setValue(address); }
}
```
几个问题
LifecycleOwner组件是如何与liveData通信的?
- SupportActivity 通过添加一个空的ReportFragment来处理生命周期状态变更回调;Fragment则在自身生命周期函数中处理。
- LifecycleOwner组件,通过LifecycleRegistry类中handleLifecycleEvent -> dispatchEvent方法与liveData通信,从而是liveData具有自动感知组件生命周期的能力。
- 组件销毁时,LifecycleRegistry会通知liveData移除observer。
ViewModel如何做到一直在内存中,直到Activity销毁或Fragment被移除时才被清除的?
1.x.x版本实现
- Activity或Fragment会添加一个空的HolderFragment,而ViewModelStore实例被HolderFragment持有,所以就保证了整个生命周期中ViewModelStore实例始终唯一,也就保证了其缓存的ViewModel实例会一直存在直到组件销毁(在onDestroy中会调用ViewModelStore.clear()方法清除其缓存的ViewModel实例)。
- 由于这个HolderFragment设置了setRetainInstance(true), 这样在Activity重建时它不会执行onDestroy回调,这就是它能度过配置变更的原因。
2.x.x版本实现
Activity
- 缓存:onRetainNonConfigurationInstance()回调方法中将ViewModelStore实例缓存到NonConfigurationInstances中。
- 恢复:在onCreate中通过getLastNonConfigurationInstance()获取重建前的状态并回复ViewModelStore。
Fragment
缓存:FragmentActivity.onSaveInstanceState -> Fragment.saveAllState -> Fragment.saveNonConfig,将ViewModelStore实例缓存到了FragmentManagerNonConfig中,最终通过FragmentActivity将其缓存到NonConfigurationInstances中。
回复:FragmentActivity.onCreate -> FragmentManager.restoreAllState(arg1, nonConfig) -> FragmentState.instantiate(x,x,x,nonConfig, viewModelStore)此方法会创建一个新的Fragment并将ViewModelStore变量赋值。