前言

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/apk/res/android"
    xmlns:app="http://schemas.android/apk/res-auto"
    xmlns:tools="http://schemas.android/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()
    }
}

这简短的逻辑,想必小伙伴们能够一眼就能知道。开始与暂停计时分别在onResumeonPause方法。

从未用过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/apk/res/android"
    xmlns:app="http://schemas.android/apk/res-auto"
    xmlns:tools="http://schemas.android/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。

更多推荐

Android—Jetpack教程(一)