开启成长之旅!这是我参加「日新计划 2 月更文应战」的第 4 天,点击检查活动概况
实践开发中,咱们常常需求在Activity的onResume或许onStop中进行大局资源的获取或开释,那么怎样去监控Activity生命周期改变呢?
告诉式监控
一般情况下,咱们能够在资源办理类中提供onActivityResume,onActivityStop之类的公共接口来完结该需求,这种情况下,需求在Activity内部的各个生命周期函数中手动调用资源办理类的对应函数,完结如下所示:
// 资源办理类
public class ResourceManager {
private static final String TAG = "ResourceManager";
public void onActivityResume() {
Log.d(TAG,"doing something in onActivityResume");
}
public void onActivityStop() {
Log.d(TAG,"doing something in onActivityStop");
}
}
public class NotifyAcLifecycleActivity extends AppCompatActivity {
private ResourceManager mResourceManager = new ResourceManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notify_ac_lifecycle);
}
@Override
protected void onResume() {
super.onResume();
mResourceManager.onActivityResume();
}
@Override
protected void onStop() {
super.onStop();
mResourceManager.onActivityStop();
}
}
能够看出,告诉式完结的生命周期监控具有以下明显缺陷:
- 代码侵入性强:需求在Activity中手动调用资源办理类的对应公共办法
- 耦合严重:资源办理类的公共办法和Activity生命周期函数强耦合,当资源办理类的数量发生改变时,新增或许删除,都需改动Activity代码
监听式监控
即然告诉式监控具有那么多的缺陷,那么咱们怎样来解决该问题呢?从操作意图能够看出,咱们希望在Activity生命周期改变的时分资源办理类能收到告诉,换句话说就是资源办理类能够监听到Activity的生命周期改变,说到监听,咱们天然而言的想到了规划形式中的调查者形式。
调查者形式包含了被调查者和调查者两个角色,描述的是当被调查者状况发生改变时,一切依靠于该被调查者的调查者都能够接收到告诉并根据需求完结操作
由调查者形式定义来看,Activity应该是被调查者,资源办理器应该是调查者,为进一步解耦,咱们引入接口,定义调查者接口如下所示:
public interface LifecycleObserver {
void onActivityResume();
void onActivityStop();
}
在被调查者(Activity)中告诉调查者,修正的代码如下:
public class ObserverLifecycleActivity extends AppCompatActivity {
private LifecycleObserver mObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_observer_lifecycle);
}
public void setObserver(LifecycleObserver observer) {
mObserver = observer;
}
@Override
protected void onResume() {
super.onResume();
if (mObserver != null) {
mObserver.onActivityResume();
}
}
@Override
protected void onStop() {
super.onStop();
if (mObserver != null) {
mObserver.onActivityStop();
}
}
}
使需求调查的目标完结调查者接口,并在onCreate中完结调查,代码如下:
public class ResourceManager implements LifecycleObserver{
private static final String TAG = "ResourceManager";
@Override
public void onActivityResume() {
Log.d(TAG,"doing something in onActivityResume");
}
@Override
public void onActivityStop() {
Log.d(TAG,"doing something in onActivityStop");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_observer_lifecycle);
setObserver(new ResourceManager());
}
这样就经过LifecycleObserver完结了ResourceManager调查Activity生命周期改变的操作,假如不需求接收告诉,不调用setObserver办法即可。
简略事务中,上述完结没问题,单跟着事务的逐步扩大,资源办理器可能不止一个,并且并不必定需求一向监听改变,在必定情况下,可能需求移除,接下来咱们进一步修正被调查者中关于调查者的办理,使其支撑多个调查者以及动态移除调查者,代码如下:
public class ObserverLifecycleActivity extends AppCompatActivity {
private List<LifecycleObserver> mObservers = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_observer_lifecycle);
addObserver(new ResourceManager());
}
public void addObserver(LifecycleObserver observer) {
mObservers.add(observer);
}
public void removeObserver(LifecycleObserver observer) {
mObservers.remove(observer);
}
@Override
protected void onResume() {
super.onResume();
if (mObservers != null && !mObservers.isEmpty()) {
for (LifecycleObserver observer : mObservers) {
observer.onActivityResume();
}
}
}
@Override
protected void onStop() {
super.onStop();
if (mObservers != null && !mObservers.isEmpty()) {
for (LifecycleObserver observer : mObservers) {
observer.onActivityStop();
}
}
}
}
从上述完结能够看出,该计划具有以下缺陷:
- 不适用于多Activity场景
- 依然需求耦合Activity的addObserver和removeObserver办法
ActivityLifecycleCallbacks
上面都是开发者完结的,那么体系内部有没有现已完结的计划呢?检查源码,能够找到ActivityLifecycleCallbacks,其定义如下:
public interface ActivityLifecycleCallbacks {
/**
* Called as the first step of the Activity being created. This is always called before
* {@link Activity#onCreate}.
*/
default void onActivityPreCreated(@NonNull Activity activity,
@Nullable Bundle savedInstanceState) {
}
/**
* Called when the Activity calls {@link Activity#onCreate super.onCreate()}.
*/
void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState);
/**
* Called as the last step of the Activity being created. This is always called after
* {@link Activity#onCreate}.
*/
default void onActivityPostCreated(@NonNull Activity activity,
@Nullable Bundle savedInstanceState) {
}
/**
* Called as the first step of the Activity being started. This is always called before
* {@link Activity#onStart}.
*/
default void onActivityPreStarted(@NonNull Activity activity) {
}
/**
* Called when the Activity calls {@link Activity#onStart super.onStart()}.
*/
void onActivityStarted(@NonNull Activity activity);
/**
* Called as the last step of the Activity being started. This is always called after
* {@link Activity#onStart}.
*/
default void onActivityPostStarted(@NonNull Activity activity) {
}
/**
* Called as the first step of the Activity being resumed. This is always called before
* {@link Activity#onResume}.
*/
default void onActivityPreResumed(@NonNull Activity activity) {
}
/**
* Called when the Activity calls {@link Activity#onResume super.onResume()}.
*/
void onActivityResumed(@NonNull Activity activity);
/**
* Called as the last step of the Activity being resumed. This is always called after
* {@link Activity#onResume} and {@link Activity#onPostResume}.
*/
default void onActivityPostResumed(@NonNull Activity activity) {
}
/**
* Called as the first step of the Activity being paused. This is always called before
* {@link Activity#onPause}.
*/
default void onActivityPrePaused(@NonNull Activity activity) {
}
/**
* Called when the Activity calls {@link Activity#onPause super.onPause()}.
*/
void onActivityPaused(@NonNull Activity activity);
/**
* Called as the last step of the Activity being paused. This is always called after
* {@link Activity#onPause}.
*/
default void onActivityPostPaused(@NonNull Activity activity) {
}
/**
* Called as the first step of the Activity being stopped. This is always called before
* {@link Activity#onStop}.
*/
default void onActivityPreStopped(@NonNull Activity activity) {
}
/**
* Called when the Activity calls {@link Activity#onStop super.onStop()}.
*/
void onActivityStopped(@NonNull Activity activity);
/**
* Called as the last step of the Activity being stopped. This is always called after
* {@link Activity#onStop}.
*/
default void onActivityPostStopped(@NonNull Activity activity) {
}
/**
* Called as the first step of the Activity saving its instance state. This is always
* called before {@link Activity#onSaveInstanceState}.
*/
default void onActivityPreSaveInstanceState(@NonNull Activity activity,
@NonNull Bundle outState) {
}
/**
* Called when the Activity calls
* {@link Activity#onSaveInstanceState super.onSaveInstanceState()}.
*/
void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState);
/**
* Called as the last step of the Activity saving its instance state. This is always
* called after{@link Activity#onSaveInstanceState}.
*/
default void onActivityPostSaveInstanceState(@NonNull Activity activity,
@NonNull Bundle outState) {
}
/**
* Called as the first step of the Activity being destroyed. This is always called before
* {@link Activity#onDestroy}.
*/
default void onActivityPreDestroyed(@NonNull Activity activity) {
}
/**
* Called when the Activity calls {@link Activity#onDestroy super.onDestroy()}.
*/
void onActivityDestroyed(@NonNull Activity activity);
/**
* Called as the last step of the Activity being destroyed. This is always called after
* {@link Activity#onDestroy}.
*/
default void onActivityPostDestroyed(@NonNull Activity activity) {
}
/**
* Called when the Activity configuration was changed.
* @hide
*/
default void onActivityConfigurationChanged(@NonNull Activity activity) {
}
}
从接口函数能够看出这是用于监听Activity生命周期事情的回调,咱们能够在Application中运用registerActivityLifecycleCallbacks注册Activity生命周期的大局监听,当有Activity的生命周期发生改变时,就会回调该接口中的办法,代码如下:
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
随后咱们就能够根据回调的Activity目标断定应该由哪个资源办理器响应对应的生命周期改变。
通常情况下,咱们能够依靠该办法完结以下需求:
- 自定义的大局的Activity栈办理
- 用户行为计算搜集
- Activity切入前后台后的资源请求或开释
- 应用前后台断定
- 页面数据保存与恢复
- … etc
Lifecycle in Jetpack
Lifecycle相关内容能够参考前面发布的系列文章:
Instrumentation
从Activity发动流程可知每个Activity生命周期改变时,ActivityThread都会经过其内部持有的Instrumentation类的目标进行分发,假如咱们能自定义Instrumentation类,用咱们自定义的Instrumentation类目标替换这个成员变量,那么天然能够经过这个自定义Instrumentation类目标来监听Activity生命周期改变。
那么怎样修正ActivityThread类的mInstrumentation成员呢?天然要用反射完结了。
自定义Instrumentation类如下所示:
public class CustomInstrumentation extends Instrumentation {
private static final String TAG = "CustomInstrumentation";
private Instrumentation mBaseInstrumentation;
public CustomInstrumentation(Instrumentation instrumentation) {
super();
mBaseInstrumentation = instrumentation;
}
@Override
public void callActivityOnResume(Activity activity) {
super.callActivityOnResume(activity);
Log.d(TAG, "callActivityOnResume " + activity.toString());
}
@Override
public void callActivityOnStop(Activity activity) {
super.callActivityOnStop(activity);
Log.d(TAG, "callActivityOnStop " + activity.toString());
}
}
在Application的attachBaseContext函数中反射修正ActivityThread的mInstrumentation成员为CustomInstrumentation类的目标,相关代码如下:
@Override
protected void attachBaseContext(Context base) {
hookInstrumentation();
super.attachBaseContext(base);
}
public void hookInstrumentation() {
Class<?> activityThread;
try{
activityThread = Class.forName("android.app.ActivityThread");
Method sCurrentActivityThread = activityThread.getDeclaredMethod("currentActivityThread");
sCurrentActivityThread.setAccessible(true);
//获取ActivityThread 目标
Object activityThreadObject = sCurrentActivityThread.invoke(null);
//获取 Instrumentation 目标
Field mInstrumentation = activityThread.getDeclaredField("mInstrumentation");
mInstrumentation.setAccessible(true);
Instrumentation instrumentation = (Instrumentation) mInstrumentation.get(activityThreadObject);
CustomInstrumentation customInstrumentation = new CustomInstrumentation(instrumentation);
//将咱们的 customInstrumentation 设置进去
mInstrumentation.set(activityThreadObject, customInstrumentation);
}catch (Exception e){
e.printStackTrace();
}
}
编写两个Activity分别为MainActivity和NotifyAcLifecycleActivity,在MainActivity中点击按钮跳转到NotifyAcLifecycleActivity,日志输出如下:
能够拿出,虽然正常署理到了Activity的生命周期改变,可是每次Activity发动都会爆出Uninitialized ActivityThread, likely app-created Instrumentation, disabling AppComponentFactory
的反常,检查源码,查找该问题的原因:
// Instrumentation.java
private ActivityThread mThread = null;
private AppComponentFactory getFactory(String pkg) {
if (pkg == null) {
Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
return AppComponentFactory.DEFAULT;
}
if (mThread == null) {
Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
+ " disabling AppComponentFactory", new Throwable());
return AppComponentFactory.DEFAULT;
}
LoadedApk apk = mThread.peekPackageInfo(pkg, true);
// This is in the case of starting up "android".
if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
return apk.getAppFactory();
}
final void basicInit(ActivityThread thread) {
mThread = thread;
}
能够看到当mThread成员为空时,会抛出该问题,mThread是在basicInit中赋值的,因为咱们创立的CustomInstrumentation目标没有调用该函数,故mThread必定为空,那么如何规避该问题呢?计划主要有两个方向
-
初始化CustomInstrumentation目标的mThread目标
反射获取原始Instrumentation目标的mThread取值,然后设置到自定义的CustomInstrumentation目标中
-
针对getFactory办法运用的函数,将函数重写,调用原始Instrumentation对应的函数
这里咱们运用第二个计划,在CustomInstrumentation中重写newActivity办法,运用原始的Instrumentation目标署理,代码如下:
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return mBaseInstrumentation.newActivity(cl, className, intent);
}
再次运行,能够看到日志中不再打印该反常,同时咱们也能正常监听到Activity生命周期改变了,详细日志如下:
综上,咱们就能够在自定义Instrumentation类的callActivityOnStop办法中过滤某些Activity,在其切入后台时进行资源的开释。
不难看出,自定义Instrumentation走通后,咱们能够在该类中接收体系的Activity发动,进而将某个目标Activity替换成咱们自己的Activity,这也是插件化完结中的一个核心过程