您现在的位置是:首页 >技术杂谈 >Android Jetpack应用指南--阅读笔记网站首页技术杂谈
Android Jetpack应用指南--阅读笔记
一、初始Jetpack
Jetpack是谷歌官方给出的一个统一的Android架构解决方案,它包含四个部分,分别是架构、UI、基础和行为,每个部分都有各自的一些组件,像架构部分就有LiveData、ViewModel、Room、Navigation、Lifecycle、DataBinding、Paging等常用组件
因为Jetpack的组件并入了AndroidX,所以想使用JetPack的话,需要先将项目迁移至AndroidX,可以通过AS菜单栏中的Refactor->Migrate to AndroidX功能选项来进行迁移,迁移前会有一个提示框,显示是否备份原项目,可以选择备份,再进行迁移(Android Support Library在版本28之后就不再更新了)
二、LifeCycle
LifeCycle组件主要是为了解决开发过程中需要感知系统组件生命周期,但又不愿与系统组件过多耦合的问题
添加Lifestyle依赖:
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
使用非常简单,对于Activity、Fragment来说,自身就已经实现了LifecycleOwner接口,我们只需要实现一个LifecycleObserver即可,然后在Activity、Fragment的onCreate方法里调用:
lifecycle.addObserver(lifecycleObserver)
在onDestroy里调用:
lifecycle.removeObserver(lifecycleObserver)
即可
Service中稍有不同,需要我们继承LifecycleService,该类提供了获取Service生命周期的方法,其它都与Service一样,然后像Activity和Fragment那样添加移除观察者就好了
如果要监听application的生命周期,监控用户回到前台、后台的时机,可以在自定义的Application的onCreate里调用:
ProcessLifecycleOwner.get().lifecycle.addObserver(MyApplicationLifecycleObserver())
即可,回到前台会调用onStart、onResume,回到后台会调用onPause、onStop,onCreate只会调用一次,onDestroy不会调用
LifestyleObserver可以实现DefaultLifecycleObserver接口,在各个生命周期回调里进行相关处理
三、Navigatioin
DeepLink在Navigation中应用的两种场景,一种是通知,通过PendingIntent构造跳转Navigation指定fragment的Intent,具体代码如下:
Navigation.findNavController(this@MainActivity, R.id.xxx)
.createDeepLink()
.setGraph()
.setDestination()
.setArguments()
.createPendingIntent()
另一种是通过外部浏览器跳转,需要先在导航图里添加<deepLink/>标签:
<fragment
android:id=""
...>
<!--id、name作为路径参数,phone、time作为查询参数-->
<!--路径参数可以为路径的子集,例如scx://example.com/id{id}/{name} 这里的id也是合法的-->
<deepLink app:uri="scx://example.com/{id}/{name}?phone={phone}&time={time}"
</fragment>
参考:https://blog.csdn.net/stephen_sun_/article/details/123339025
然后在清单文件里为Activity设置<nav-graph/>标签:
<activity android:name="">
//为Activity设置<nav-graph/>标签
<nav-graph android:value="@navigation/xxx"/>
</activity>
最后使用adb工具测试:
adb shell am start -a android.intent.action.VIEW -d "http://www.YourWebsite.com/ParamsFromUrl"
四、ViewModel
记录页面的数据,有独立的生命周期,比较简单,只记录一个感兴趣的问题解答博客:
屏幕旋转导致Activity销毁重建,ViewModel是如何恢复数据的 - 掘金 (juejin.cn)
五、LiveData
LiveData是一个可被观察的数据容器类,它将数据包装起来,使数据成为被观察者
LiveData本质上采用的是观察者模式,而且能够感知页面的生命周期,从而只在页面处于onStart和onResume状态时更新数据,如果需要在页面任何状态都能感知数据的变化,可以使用observeForever方法,不过此时一定要记着在不需要时调用removeObserver方法移除监听,避免内存泄漏
六、Room
Room包含三个部分,分别是Entity、Dao、Database,定义了表结构、查询、数据库的相关信息,Room可以与LiveData配合使用,当表数据改变时,LiveData能自动检测到数据库变化并通知到观察者,从而更新UI
参考:如何使用LiveData实现Room数据库的数据变化监听? - 掘金 (juejin.cn)
从Room2.2开始,加入了两个API,分别是createFromAsset()和createFromFile(),createFromAsset表示从asset目录下加载数据库文件并以此文件为基础创建数据库,createFromFile表示从手机存储中加载数据库文件并创建数据库,在创建数据库时可以调用,进行数据库的数据预填充
七、WorkManager
WorkManager旨在帮助开发者在后台处理不需要及时执行的任务,开发者可以设置触发条件、任务执行顺序,剩下的交由WorkManager处理就可以了,WorkManager会在满足触发条件后的某个时刻开始执行任务,WorkManager宣称能够保证任务一定得到执行,无论是杀死app还是重启设备,但是在国内真机上测试结果却不一定,可能是国内系统修改的缘故,所以使用WorkManager时需要考虑这一点
WorkManager使用流程:
1.继承Worker类并重写doWork执行耗时任务,并根据执行结果返回相对应的Result(Result.success()、Result.failure()、Result.retry())
2.构造Constraints类对象设置任务触发条件,并设置给WorkRequest,构造一个任务请求对象,WorkRequest还可以设置tag、延迟执行时间、指数退避策略、给Worker传递参数等
3.将任务提交给系统:
WorkManager.getInstance(this).enqueue(workRequest)
4.通过获取WorkInfo观察任务状态
WorkManager.getInstance(this).getWorkInfosByTag()
或
WorkManager.getInstance(this).getWorkInfosByTagLiveData()
5.取消任务
WorkManager.getInstance(this).cancelAllWork()
八、Databinding
1.启用databind
dataBinding{
enabled=true
}
2.xml中使用layout做根节点,使用variable作为引入数据,还可以在data中引入静态类,在控件中进行使用
<layout
...
<data>
<import type="引入的静态类"/>
<variable
name=""
type=""/>
</data>
//使用时用@{variable中name}即可
...
</layout>
3.在二级页面绑定
在include标签里,使用app:name=@{variable.name}其中name是二级页面中data里定义的<variable>里定义的变量名
4.自定义BindingAdapter
在类中定义相应的静态方法,添加@BindingAdapter("name")注解,其中name是在xml中使用的属性名字(如app:name=""),确保布局文件最外层包含以下命名空间,这样才能调用那些使用@BindingAdapter注解定义的静态方法,静态方法的第一个参数是控件名字,比如要给ImageView自定义属性,第一个参数就是ImageView imageView,第二个参数或后边多个参数是自定义属性,如下:
//命名空间
xmlns:app="http://***.android.com/apk/res-auto"
//BindingAdapter实例
@BindingAdapter(value={"image","defaultImageResource"},requireAll=false)
public static void setImage(ImageView imageView,String imageUrl,int imageResource){
if(!TextUtils.isEmpty(imageUrl){
Glide.with(context).load(imageUrl).into(imageView);
}else{
imageView.setImageResource(imageResource);
}
}
//调用:
<ImageView
...
app:image=""
app:defaultImageResource=""
...
</ImageView>
//如果有多个属性可以用上面那种形式,如果只有一个可以省去value=,直接写属性名即可;requireAll表
//示这些参数是否都要赋值