前言
Jetpack的热度,想必大家有目共睹!现在越来越多的公司招聘要求Jetpack是必会项目,Google也在疯狂的更新Jetpack组件,热度完全不亚于Kotlin!所以说呢?还不卷起来么?
那么Jetpack是什么呢?
1、初始Jetpack
1.1 什么是Jetpack?
如图所示
Jetpack是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
1.2 为何使用Jetpack?
- 遵循最佳做法
- Android Jetpack 组件采用最新的设计方法构建,具有向后兼容性,可以减少崩溃和内存泄露。
- 消除样板代码。
- Android Jetpack 可以管理各种繁琐的Activity(如:后台任务、导航和生命周期管理),以便你可以专注于打造出色的应用。
- 减少不一致
- 这些库可在各种Android 版本和设备中以一致的方式运作,助你降低复杂性!
1.3 Jetpack与AndroidX
- AndroidX命名空间中包含Android Jetpack库
- AndroidX代替Android Support Library
- AAC(Android Architecture Component) 中的组件并入AndroidX
- 其他一些需要频繁更新和迭代的特性也并入了AndroidX
2、LifeCycle
2.1 LifeCycle的作用
如图所示
简单的说就是用来监听Activity与Fragment的生命周期变化
2.2 LifeCycle应用
- 使用Lifecycle解耦页面与组件
- 使用LifecycleService解耦Service与组件
- 使用ProcessLifecycleOwner监听应用程序生命周期
概念说了一大堆了!该实战了!
2.3 实战一(未使用LifeCycle)
布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Chronometer
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
这里可以看出,里面定义了一个计时器组件。来看看实现逻辑!
class Step1Activity : AppCompatActivity() {
private var chronometer: Chronometer? = null
private var elapsedTime: Long = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
chronometer = findViewById(R.id.chronometer)
}
override fun onResume() {
super.onResume()
chronometer!!.base = SystemClock.elapsedRealtime() - elapsedTime
chronometer!!.start()
}
override fun onPause() {
super.onPause()
elapsedTime = SystemClock.elapsedRealtime() - chronometer!!.base
chronometer!!.stop()
}
}
这简短的逻辑,想必小伙伴们能够一眼就能知道。开始与暂停计时分别在onResume
与onPause
方法。
从未用过Jetpack
的你,感觉这样写好像并没有什么问题!
但是仔细考虑下,这样写是不是将控件与生命周期绑定的太死了?
而且当我们长周期的变量在短周期使用,当短周期结束时,如果没有及时释放还会造成内存泄露!
因此,来看看使用Jetpack将会带来怎样的故事?
2.4 实战二(使用LifeCycle)
2.4.1 自定义计时器控件
@SuppressLint("ViewConstructor")
class MyChronometer : Chronometer, LifecycleObserver {
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
var elapsedTime: Long = 0
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
open fun startMeter() {
base = SystemClock.elapsedRealtime() - elapsedTime
start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
open fun stopMeter() {
elapsedTime = SystemClock.elapsedRealtime() - base
stop()
}
}
这时,我们看到:
- 在这自定义了控件,继承了
Chronometer
计时器,实现了LifecycleObserver
接口 - 将开始计时与暂停计时对应的逻辑转移至自定义控件里,并添加了对应的注解
2.4.2 使用控件
将自定义控件添加至布局里(这里我就不贴布局代码了吧)
最新的activity:
class Step2Activity : AppCompatActivity() {
private var chronometer: MyChronometer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
chronometer = findViewById(R.id.chronometer)
lifecycle.addObserver(chronometer!!)
}
}
这里我们看到,使用LifeCycle后,对应控件根本不需要和activity生命周期绑死了,只需要添加一句lifecycle.addObserver(chronometer!!)
就OK了!
现在我们解决了activity的生命周期耦合度(Fragment同理,读者可以尝试),那Service呢?将是怎样呢?
2.5 实战三(LifecycleService)
当然Google粑粑肯定为我们考虑好了的,那就是对应的Service
使用LifecycleService
。
看看LifecycleService
源码:
public class LifecycleService extends Service implements LifecycleOwner {
....略
}
看到这句,就确定了LifecycleService
就是Service
,所以可以放心大胆的使用!
2.5.1 自定义Service
这里我就用定位服务举例
MyLocationService.kt
class MyLocationService : LifecycleService {
constructor() {
Log.d("hqk", "MyLocationService")
val observer = MyLocationObserver(this)
lifecycle.addObserver(observer)
}
}
这里并没有在Service
对应生命周期里实现对应的定位服务,而是使用了自定义的MyLocationObserver
,来看看它长啥样?
MyLocationObserver.kt
class MyLocationObserver : LifecycleObserver {
private var context: Context? = null
private var locationManager: LocationManager? = null
private var locationListener: MyLocationListener? = null
constructor(context: Context) {
this.context = context
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private fun startGetLocation() {
Log.d("hqk", "startGetLocation")
locationManager = context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
//定位监听
locationListener = MyLocationListener()
//权限校验
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
//权限通过,开启定位
locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 3000, 1f,
locationListener!! //定位回调监听
)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private fun stopGetLocation() {
Log.d("hqk", "stopGetLocation")
locationManager!!.removeUpdates(locationListener!!)
}
internal class MyLocationListener : LocationListener {
//定位成功或者位置发生改变时将会回到该方法
override fun onLocationChanged(location: Location) {
Log.d("hqk", "location changed:$location")
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
}
代码解析
- 这里就实现了以前service实现的核心逻辑。
- 在对应方法添加了对应的注解,表示和对应生命周期一致。
2.5.2 权限注册
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
2.5.3 布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Step3Activity">
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startGps"
android:text="开始"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.354" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="stopGps"
android:text="停止"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.506"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.632"
tools:ignore="OnClick" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.5.4 对应Activity
class Step3Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_two)
}
fun startGps(view: View) {
startService(Intent(this, MyLocationService::class.java))
}
fun stopGps(view: View) {
stopService(Intent(this, MyLocationService::class.java))
}
}
注意:这里我就没有写什么权限申请了,偷下懒,而是直接去设置里改的权限。
运行效果
点击开始按钮时:
/com.hqk.lifecycle D/hqk: MyLocationService
/com.hqk.lifecycle D/hqk: startGetLocation
/com.hqk.lifecycle D/hqk: location changed:Location[gps 30.705794,104.041993 acc=1 et=+58m34s576ms alt=0.0 vel=0.0 bear=0.0 {Bundle[EMPTY_PARCEL]}]
位置发生改变时:
/com.hqk.lifecycle D/hqk: location changed:Location[gps 30.667559,104.034240 acc=1 et=+59m55s464ms alt=0.0 vel=0.0 bear=0.0 {Bundle[mParcelledData.dataSize=40]}]
点击结束按钮时:
/com.hqk.lifecycle D/hqk: stopGetLocation
这里讲解了对应activity与service,当然也可以监听对应App的生命周期。
2.6 实战四(监听app生命周期)
2.6.1 自定义MyApplication
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle
.addObserver(ApplicationObserver())
}
}
2.6.2 对应Observer
ApplicationObserver.kt
class ApplicationObserver : LifecycleObserver {
private val tag = "hqk"
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
Log.d(tag, "Lifecycle.Event.ON_CREATE")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
Log.d(tag, "Lifecycle.Event.ON_START")
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
Log.d(tag, "Lifecycle.Event.ON_RESUME")
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
Log.d(tag, "Lifecycle.Event.ON_PAUSE")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
Log.d(tag, "Lifecycle.Event.ON_STOP")
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
Log.d(tag, "Lifecycle.Event.ON_DESTROY")
}
}
运行效果
进入App时
/com.hqk.lifecycle D/hqk: Lifecycle.Event.ON_CREATE
/com.hqk.lifecycle D/hqk: Lifecycle.Event.ON_START
/com.hqk.lifecycle D/hqk: Lifecycle.Event.ON_RESUME
退出后台/结束运行时
/com.hqk.lifecycle D/hqk: Lifecycle.Event.ON_PAUSE
/com.hqk.lifecycle D/hqk: Lifecycle.Event.ON_STOP
2.6.3 注意事项
这里的ProcessLifecycleOwner.get().lifecycle
- 针对整个应用程序的监听,与activity数量无关!
-
Lifecycle.Event.ON_CREATE
只会调用一次。 -
Lifecycle.Event.ON_DESTROY
永远不会被调用,Google粑粑不可能让开发者在这搞事情
2.7 LifeCycle的好处
通过这几个实战我们能够发现:
- 帮助开发者建立可感知生命周期的组件
- 组件在其内部管理自己的生命周期,从而降低模块耦合度
- 降低内存泄露发生的可能性
- Activity、Fragment、Service、Application均有LifeCycle支持
结束语
好了,本篇到这里差不多结束了,相信你对Jetpack对应的LifeCycle有了一定的认知,在下一篇中,将会讲解Jetpack里面的ViewModel与LiveData。