Lifecycle是Jetpack提供的一个用于监听生命周期的库。我们知道在使用Activity和Fragment的时候,特别是两者一起使用的时候,生命周期将变得非常的复杂。而且我们需要在Activity和Fragment的生命周期方法里面执行非常多的操作,如地理位置,打开关闭资源等。这会造成很高的耦合。Lifecycle就是为了减低生命周期的耦合而设计的。目的是让各种资源自己监听生命周期变化,在独立的类里面实现相应的生命周期逻辑。
Lifecycle已经包含在androidx里面,也就是下面的包,默认情况下,gradle已经有下面的声明了。
implementation 'androidx.appcompat:appcompat:1.2.0'
这里有一个特别的地方。就是lifecycle-extensions这个库,只要引用这个库就会把lifecycle里面的所有库都引用进来。
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
你也可以手动的引用你需要的库。推荐最开始还是用lifecycle-extensions这个库,避免麻烦。lifecycle-extensions这个库里面的所有API都已经被废弃。
dependencies {
def lifecycle_version = "2.5.0-rc01"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
}
这里推荐使用2.2.0这个版本,因为这个版本提供的ViewModelProvider这个类多出了一个参数的构造方法,具体后面会用到。
1.计算真实运行时间的例子
我们要做这样的一个功能。运行app的时候计算运行时间,app退到后台的时候不计算时间。app继续运行,继续计算运行时间。
我们使用Chronometer这个系统提供的组件来实现这个功能。在onResume的时候开始计时,onPause的时候结束计时。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".lifecycle.LifecycleTimerActivity">
<Chronometer
android:id="@+id/chronometer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:gravity="center"
/>
</RelativeLayout>
public class LifecycleTimerActivity extends AppCompatActivity {
private Chronometer chronometer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle_timer);
chronometer = findViewById(R.id.chronometer);
}
@Override
protected void onResume() {
super.onResume();
Log.d("LifecycleTimerActivity", "onResume");
chronometer.start();
}
@Override
protected void onPause() {
super.onPause();
chronometer.stop();
}
}
上面的代码的运行效果如下,我们在运行到3秒的时候按home键程序退到后台,调用onPause方法。再过来7秒后,我们把app运行到前台。对应的计时也变成了10秒,可见在这种情况下,chronometer即使在后台运行也是会计算时间的。
我们现在有一个需求,就是后台运行时间我们算在“休息时间”里面,不计算入总运行时间。例如,我们在3秒的时候点击home,程序进入后台,过来几秒后,手动让程序回到前台,这时间我们的app还是继续从3秒开始计时。要实现这个功能,只需要把代码改成下面的样子。
elapsedRealtime()这个方法表示系统自开机以来所运行的时间,包括休眠,锁屏。
setBase()实际就是传入一个时间值给mBase变量,这个变量就是个long类型的表示时间的变量。
elapse这个我们自己定义的变量非常关键,用来计算真实运行的时间。在onPause的时候调用。具体逻辑看下面的代码注释。
public class LifecycleTimerActivity extends AppCompatActivity {
private Chronometer chronometer;
private long elapse;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle_timer);
chronometer = findViewById(R.id.chronometer);
}
@Override
protected void onResume() {
super.onResume();
Log.d("LifecycleTimerActivity", "onResume");
//getBase获得的时间值就是等于elapsedRealtime的值。
//减掉elapse意义是以后每次调用chronometer.getBase()都少了真实运行时间
chronometer.setBase(SystemClock.elapsedRealtime() - elapse);
chronometer.start();
}
@Override
protected void onPause() {
super.onPause();
Log.d("LifecycleTimerActivity", "onPause");
//计算出真实运行时间
elapse = SystemClock.elapsedRealtime() - chronometer.getBase();
chronometer.stop();
}
}
上面的代码已经完成了我们需要的功能。有没有发现上面代码有什么问题?这仅仅是一个小功能,要是我们有很多代码都写在声明周期里面,生命周期方法将变得非常臃肿。耦合度非常的高。为了解决这个问题,就要使用我们今天的主角Lifecycle了。
2.使用Lifecycle改进
我们可以把前面的逻辑做一个封装,问题的关键是我们怎么感知生命周期。通过实现LifecycleObserver接口就可以感知生命周期了,这个能力是SDK已经帮我们实现了,ComponentActivity已经实现了感知生命周期的功能。所以我们可以直接使用。@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)可以和onResume方法绑定,其它生命周期方法也是一样。
class Timer extends Chronometer implements LifecycleObserver {
private long elapse;
public Timer(Context context) {
super(context);
}
public Timer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void startTimer() {
setBase(SystemClock.elapsedRealtime() - elapse);
start();
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void stopTimer() {
elapse = SystemClock.elapsedRealtime() - getBase();
stop();
}
}
在Activity里面使用封装后的代码:
public class LifecycleTimerActivity extends AppCompatActivity {
private Timer chronometer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle_timer);
chronometer = findViewById(R.id.chronometer);
}
@Override
protected void onResume() {
super.onResume();
Log.d("LifecycleTimerActivity", "onResume");
chronometer.startTimer();
}
@Override
protected void onPause() {
super.onPause();
Log.d("LifecycleTimerActivity", "onPause");
//计算出真实运行时间
chronometer.stopTimer();
}
}
通过封装加Lifecycle,代码得到了简化,耦合度也大大减低了。Lifecycle还是非常有用的。
3.结合Service例子
在Service里面我们添加Lifecycle观察者。
public class LocationService extends LifecycleService {
public LocationService() {
LocationObsever obsever=new LocationObsever(this);
getLifecycle().addObserver(obsever);
}
}
最主要的实现是我们的LocationObsever。
class LocationObsever implements LifecycleObserver {
private final Context context;
private LocationManager locationManager;
private MyLoactionListener myLoactionListener;
public LocationObsever(Context context) {
this.context = context;
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void startLocation() {
Log.d("LocationObsever", "startLocation");
locationManager = (LocationManager) context.getSystemService(Service.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
myLoactionListener = new MyLoactionListener();
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1,myLoactionListener);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void stopLocation() {
Log.d("LocationObsever", "stopLocation");
locationManager.removeUpdates(myLoactionListener);
}
static class MyLoactionListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
Log.d("MyLoactionListener", location.toString());
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
}
public class LocationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
}
public void start(View view) {
startService(new Intent(this, LocationService.class));
}
public void stop(View view) {
stopService(new Intent(this,LocationService.class));
}
}
最主要的就是LocationManager这个类,可以获取经纬度等信息。可以通过下面的adb代码改变。
adb -s emulator-5554 emu geo fix -122.08400000000002 37.421998333333335
adb -s emulator-5554 emu geo fix -122.08400000000002 38.421998333333335
4.application配合Lifecycle
Application也是可以被Lifecycle监听的,当然和一般的activity不同,Application的onDestory永远不会被调用。代码也是非常的简单。
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationObsever());
}
}
public class ApplicationObsever implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
Log.d("ApplicationObsever", "onStart");
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
Log.d("ApplicationObsever", "onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
Log.d("ApplicationObsever", "onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
Log.d("ApplicationObsever", "onPause");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
Log.d("ApplicationObsever", "onStop");
}
}