Jetpack 包含一系列 Android 库,它们都采用最佳做法并在 Android 应用中提供向后兼容性。
Jetpack 库可以单独使用,也可以组合使用,以满足应用的不同需求。
例如:
WorkManager - 满足您的后台调度需求。
Room - 实现数据存储持久性。
Navigation - 管理应用导航流程。
CameraX - 满足相机应用需求。
实现方式
所有 Jetpack 组件都可在 Google Maven 代码库中找到。 在应用中使用
Jetpack 库:打开 settings.gradle 文件,将 google() 代码库添加到 dependencyResolutionManagement { repositories
{…}} 块中,如下所示:
1 | dependencyResolutionManagement { |
如需详细了解如何使用 Jetpack,请查看以下页面:
从零到一搭建
我的Demo采用MVVM的设计模式,框架图如下:
Jetpack组件:
- Navigation:一个用于管理Fragment切换的工具类,可视化、可绑定控件、支持动画等是其优点。
- Data Binding:不用说,都知道,加速MVVM的创建。
Lifecycle:虽然我没有写文章介绍,但是不代表它的作用不够强大,他是我们能够处理Activity和Fragment的生命周期的重要原因,在AndroidX的Fragment和Activity已经对Lifecycle提供了默认支持。
- ViewModel:当做MVVM的ViewModel层,并具有声明周期意识的处理和UI相关的数据。
- LiveData:同RxJava的作用一样,对数据进行监听,优点就是无需处理生命周期、无内存泄漏等。
- Room:强大的ORM数据库框架。
- Paging:易于使用的数据分页库,支持RecyclerView。
- WorkManager:灵活、简单、延迟和保证执行的后台任务处理库。
使用踩坑
Navigation:
1.当我们快速点击按钮会重复调用navigate()导致异常如下:
1 | java.lang.IllegalArgumentException: Navigation action / destination com.soushin.tinmvvm:id / action_homeFragment_to_categoryFragment cannot be found from the current destination Destination( |
这是因为第一次调用navigate()
后当前页面已经换了,而我们的action是明确了起点和终点的,所以当第二次调用的时候起点不再是HomeFragment就会报上述异常,这在页面跳转时添加转场动画会显得非常明显(
转场动画有duration),只需要在跳转前判断currentDestination是否是当前页面的destination即可。
1 | if (Navigation.findNavController(v).currentDestination?.id != R.id.homeFragment) return |
2.出现无法找到导航图的问题.检查在xml文件中,是否设置了navGraph的资源文件; 如果设置了还是无法找到,请点击右上角的扳手的图标;
使用组件自带fragmentNavigator跳转时候,出现重复新建fragment对象问题,解决方案:请自定义fragmentNavigator;
3.传参数问题:
我是在重构项目中开始使用的,在别的页面开始进行navigation的使用的时候,需要把上一个页面的参数传进来,所以我会优先考虑使用FragmentManager的进行传递(因为这不是navigation的范围了),但是有个很重要的因素,就是他们使用的FragmentManager不是同一个,所以会导致数据传递失败了!!!
解决方法:
- 把上一个页面的参数,传到承载navigation容器的Activity/Fragment中,然后然后通过以下方式,把数据传入到起始目的地
1 | navController.setGraph(R.navigation.nav_setting, bundleOf(FRAGMENT_DATA_IS_SET to ISSETPASSWORD)) |
- fragment之间传递参数
1 | 发送数据: |
- fragment向activity传递参数
1 | 发送数据: |
- 如果Fragment中的参数需要用到其他页面,但并是不导航图的下一个目的地,请使用FragmentManager进行数据传递 同级Fragment中:
1 | 发送数据: |
父Fragment与子Fragment之间:
1 | 父Fragment: |
Navigation的底层对Fragment的管理直接采取了替换的方式,虽然它可以配合BottomNavigationView使用,但每次都重新加载显然是不合理的,不推荐使用。
LiveData
优点:对数据进行监听,拥有可观察、生命周期感知、、无内存泄漏等的特点。 缺点:
- 只能在主线程中订阅和移除观察者
- 数据丢失问题,在数据生产速度 > 数据消费速度时,LiveData 无法观察者能够接收到全部数据。比如在子线程大量 postValue 数据但主线程消费跟不上时,中间就会有一部分数据被忽略。
- 在 Fragment 中出现 LiveData 同样数据多次回调的问题,针对这个问题,Google 一位大神在 Stack Overflow 实现了一个复写类 SingleLiveEvent.
- observeForever 和 removeObserver 方法要配套使用,否则会导致内存泄漏问题
- LiveData天生就是粘性的,当我们重复订阅的时候,会返回最后一次结果. UnPeek-LiveData开源库可以解决这个问题。 LiveData 的替代者: RxJava: RxJava
是第三方组织 ReactiveX 开发的组件,Rx 是一个包括 Java、Go 等语言在内的多语言数据流框架。功能强大是它的优势,支持大量丰富的操作符,也支持线程切换和背压。然而 Rx
的学习门槛过高,对开发反而是一种新的负担,也会带来误用的风险。 Kotlin Flow: Kotlin Flow 是基于 Kotlin 协程基础能力搭建的一套数据流框架,从功能复杂性上看是介于
LiveData 和 RxJava 之间的解决方案。Kotlin Flow 拥有比 LiveData 更丰富的能力,但裁剪了 RxJava 大量复杂的操作符,做得更加精简。并且在 Kotlin
协程的加持下,Kotlin Flow 目前是 Google 主推的数据流框架。
Room
- 数据库加密不友好,推荐使用saferoom开源库适配
- 数据库版本升级迁移不友好,仅支持增删列字段,增删索引必须删除表重新创建; 新增字段必须添加默认值,建议项目创建时就添加默认值,索引一个字段单独使用普通索引,不建议使用联合索引即Index(
字段1,字段2);
Paging
- 仅适合加载查看数据的场景,不适合增删改的场景且无增删改方法。一旦增删改之后,Paging分页逻辑将失去作用。
- 界面不可见后一段时间切回来时会重新加载数据。 解决方法: 1)对PagingFlow添加cacheIn(viewModelScope)。 2)不使用CoroutineLiveData,直接用
lifecycleScope.launchWhenCreated 和 flow 来接收 PagingData 数据。
WorkManager
- 适配android12,版本必须在2.7.1之上
- 定时任务不一定准时执行,但一定会执行
总结
1.Android Jetpack组件中的很多库都对其他库提供了支持,比如Room和Paging就对LiveData提供了支持。
2.向后兼容:基本上每个组件都对低版本提供了支持。支持RxJava:由于RxJava强大的生态环境,几乎和数据相关的组件都对RxJava提供了支持。
3.减少代码量:以Data Binding + ViewModel + LiveData或RxJava构建的MVVM模式能够显著减少代码量,比较平时使用的MVP模式也会更加方便,无需主动更新UI。
4.无需捆绑:Android Jetpack系列组件可以无需捆绑使用,你如果只想用里面的单个库,那么就可以仅仅依赖一个库。