1 Lifecycle的作用
Lifecycle是用来解耦普通的控件和系统组件(Application、Activity和Service等),一般普通组件都会高度依赖系统组件的生命周期,可能会在系统组件的生命周期中管理大量普通组件,造成系统组件逻辑臃肿。
2 Lifecycle的应用
2.1 使用Lifecycle解耦页面与组件
我们用一个使用Chronometer控件实现显示界面处于前台状态时的时长做样例。按照以往的编码习惯我们可能会写出如下的代码。
package com.android.lifecycle;
/**
* 本样例实现一个Chronometer控件用于显示界面处于前台状态时的时长
*/
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.Chronometer;
public class MainActivity extends AppCompatActivity {
private Chronometer chronometer;
private long elapsedTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ctrl+alt+v 快捷生成方法内变量
// ctrl+alt+f 快捷将方法内变量转全局变量
chronometer = findViewById(R.id.chronometer);
}
@Override
protected void onResume() {
super.onResume();
chronometer.setBase(SystemClock.elapsedRealtime() - elapsedTime);
chronometer.start();
}
@Override
protected void onPause() {
super.onPause();
// elapsedTime 用于统计界面处于前台时间
elapsedTime = SystemClock.elapsedRealtime() - chronometer.getBase();
chronometer.stop();
}
}
可以从样例代码中看出,我们需要在Activity的生命周期中对Chronometer控件进行管理,不仅如此,为了管理Chronometer控件,我们还需要在Activity中添加一些变量,如此处的elapsedTime,这些其实都不是Activity应该关心的内容,或者说,这些逻辑和变量,和控件本身关联更大,应该交给控件进行处理。
此时引入Lifecycle,创建一个可以“感知”Activity生命周期的Chronometer控件,它可以自动的根据Activity不同的生命周期对自身进行管理。
package com.android.lifecycle.views;
import android.content.Context;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.widget.Chronometer;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
public class LifeCycleChronometer extends Chronometer implements LifecycleObserver {
private long elapsedTime;
public LifeCycleChronometer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void startMeter() {
setBase(SystemClock.elapsedRealtime() - elapsedTime);
start();
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
private void stopMeter() {
elapsedTime = SystemClock.elapsedRealtime() - getBase();
stop();
}
}
通过继承LifecycleObserver接口(这个接口是个空接口,只做标识作用)。我们将需要在Activity不同生命周期执行的方法放到控件内部,通过注解标识需要在哪些生命周期调用这些方法,使得Activity无需再关心管理这些控件,改动后的Activity的代码如下。
package com.android.lifecycle;
/**
* 本样例实现一个Chronometer控件用于显示界面处于前台状态时的时长
*/
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.android.lifecycle.views.LifeCycleChronometer;
public class MainActivity extends AppCompatActivity {
private LifeCycleChronometer chronometer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
getLifecycle().addObserver(chronometer);
}
}
可出看到改动后的Activity中,不再有那些和管理控件相关的逻辑与变量。这样做有如下的优点,
1.精简了Activity内部的逻辑,避免了Activity的臃肿。Activity唯一需要知道的就是谁在观察它。
2.解耦了Activity和控件,我们在写这个LifecycleChronometer控件时其实根本不关心它最后会被用到哪个Activity中,只需要知道何时调用自身哪些逻辑即可,这些都是通过Lifecycle来实现。
2.2 使用LifecycleService解耦Service和控件
在Lifecycle组件包中,还提供了实现LifecycleOwner接口的LifecycleService类,借助该类,我们还可以将控件同Service进行解耦。通过编写一个获取位置信息的样例来演示LifecycleService,该样例会启动一个服务,在服务启动时,我们会去获取位置信息,并监听位置变化,在服务销毁时会自动的停止获取位置信息。
package com.android.lifecycle.services;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.lifecycle.LifecycleService;
import com.android.lifecycle.LocationObserver;
public class LocationService extends LifecycleService {
private static final String TAG = "LocationService";
public LocationService() {
Log.d(TAG, "init...");
LocationObserver observer = new LocationObserver(this);
getLifecycle().addObserver(observer);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
上面是服务类的具体实现,可以看到,同之前的样例一样,Service中并未有任何管理获取位置信息的逻辑,Service只需关心谁需要“观察”自己。
package com.android.lifecycle;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
public class LocationObserver implements LifecycleObserver {
private static final String TAG = "LocationObserver";
private final Context context;
private LocationManager locationManager;
private LocationListenerImpl locationListener;
public LocationObserver(Context context) {
this.context = context;
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void startGetLocation() {
Log.d(TAG, "startGetLocation...");
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListenerImpl();
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, 3000L, 1, locationListener);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void stopGetLocation() {
Log.d(TAG, "stopGetLocation...");
locationManager.removeUpdates(locationListener);
}
static class LocationListenerImpl implements LocationListener {
private static final String TAG = "LocationListenerImpl";
@Override
public void onLocationChanged(@NonNull Location location) {
Log.d(TAG, "location changed: " + location.toString());
}
}
}
同样,我们将获取位置的控制逻辑部分留在了LocationObserver这个“观察者”内部,它才是知道何时去获取位置,何时去停止获取位置的角色。通过这种“观察”——“被观察”的模式,我们实现了代码的“高内聚,低耦合”。
3.3 使用ProcessLifecycleOwner解耦Application和控件
借助ProcessLifecycleOwner,我们还可以实现对于Application生命周期的观察,从而实现解耦Application和控件。
package com.android.lifecycle;
import android.app.Application;
import androidx.lifecycle.ProcessLifecycleOwner;
public class LifeCycleApp extends Application {
private static final String TAG = "LifeCycleApp";
private final LifeCycleAppObserver observer;
public LifeCycleApp() {
super();
observer = new LifeCycleAppObserver();
ProcessLifecycleOwner.get().getLifecycle().addObserver(observer);
}
}
和前面Activity还有LifecycleService不同,对于Application,是通过ProcessLifecycle类的get方法获取到该类的单例,再将LifecycleObserver注入进去。
package com.android.lifecycle;
import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
public class LifeCycleAppObserver implements LifecycleObserver {
private static final String TAG = "LifeCycleAppObserver";
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onAppCreate() {
Log.d(TAG, "onAppCreate...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppStart() {
Log.d(TAG, "onAppStart...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void onAppResume() {
Log.d(TAG, "onAppResume...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
private void onAppPause() {
Log.d(TAG, "onAppPause...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppStop() {
Log.d(TAG, "onAppStop...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void onAppDestroy() {
Log.d(TAG, "onAppDestroy...");
}
}
“观察者”的类的逻辑基本一致,通过注解来实现在不同的生命周期调用不同的方法。
3 Lifecycle总结
其实Lifecycle本质上是基于观察者模式来实现,在Lifecycle结构中,系统控件(Application、Activity和Service等)是被观察者,我们实现了LifeycleObserver接口的控件是观察者。将系统控件主动管理其他控件这一模式转换为其他控件观察系统控件的“状态”来决定自身的状态的模式。
4 待探索
我们在样例中编写的那些通过注解实现需要在特定的生命周期时进行调用的方法,都是private类型的方法,但是却可以通过Lifecycle包在其他类中进行调用(毕竟我们没有在自己的代码中进行调用用,且按照一般观察者模式,这些回调方法,一般是在其他类中进行回调)。因此我推测,应该是利用了反射进行注解的检索,并进行方法调用。
I 附录
在LifecycleService的样例中,我们可以通过adb命令对虚拟Android设备(实体手机不适用)进行位置修改,来验证位置改变。
具体命令 $ adb -s emu geo fix
命令样例 $ adb -s emulator-5554 emu geo fix 121.49612 31.24010
虚拟设备名称可以通过 adb devices 命令获取。