SDK中为我们提供了非常好的对Activity进行测试的方式,那么Activity的内部机制是如何支持的呢?比如如何在Activity的生命周期变化中加入测试代码?如何监控到Activity的各种变化?如何获得Activity启动的性能参数?如何自动向Activity发送按键消息以进行测试?带着这些问题,我们要再次深入Activity源码来一探究竟。
首先想到的就是,如果要想监控到Activity生命周期的变化,必然会在Create或Start等处有代码来进行处理,所以我们把重点放在Activity那近4000行代码中与此相关的函数部分。
遗憾的是在onCreate()、onStart()等处没有发现任何有效的线索,不过不要气馁,继续向下找。
在startActivityForResult()函数中,mInstrumentation.execStartActivity()一句让我们看到至少有一个mInstrumentation的对象受委托在启动Activity,这个委托是有可能加入监控动作的。
public void startActivityForResult(Intent intent, int requestCode) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
继续向下,在以perform开头的几个函数中,我们再次发现了对mInstrumentation对象的调用。例如performStart()函数。
final void performStart() {
mCalled = false;
mInstrumentation.callActivityOnStart(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onStart()");
}
}
到此为止,我们必须得对Instrumentation类进行深入了解了,方式有二种,一是通过SDK了解该类的功能和接口,二是直接看源码。如果二种方式都用也没有问题,先通过SDK,我们知道了该类是一个基类,会在我们自己的应用程序运行之前被系统实例化,以允许我们监控所有与系统的交互(太伟大了),实现的方式是通过在AndroidManifest.xml文件中加入 <instrumentation> 标签。看来这个一定是我们想要找到的答案了,赶紧打开源码来学习一下吧。
整体上看,该类的接口主要有以下几类:对Activity监控对象的处理接口,Activity状态改变时的回调通知接口,生成Activity和Application的接口,向Activity发送事件通知的接口,性能处理的接口等。
下面我们就找几个典型的函数来看一下Instrumentation与Activity的交互机制。
先来看callActivityOnCreate()函数。
public void callActivityOnCreate(Activity activity, Bundle icicle) {
if (mWaitingActivities != null) {
synchronized (mSync) {
final int N = mWaitingActivities.size();
for (int i=0; i<N; i++) {
final ActivityWaiter aw = mWaitingActivities.get(i);
final Intent intent = aw.intent;
if (intent.filterEquals(activity.getIntent())) {
aw.activity = activity;
mMessageQueue.addIdleHandler(new ActivityGoing(aw));
}
}
}
}
activity.onCreate(icicle);
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
}
}
}
}
注意activity.onCreate(icicle);这句的含义,调用了我们自己的Activity重写的onCreate()函数。
在来看我们前文提到的execStartActivity()函数。
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
……// 处理ActivityMonitor
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
requestCode, false, false);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
在这里,处理完ActivityMonitor后,真正启动一个Activity的是ActivityManagerNative.getDefault().startActivity()语句,这也符合我们的预期,真正的Activity的操作应该是由ActivityManager来完成的,当然对于ActivityManager来说,内部还有很复杂的代码和类关系,以后有时间我们再来一一拆解吧。
还有一个很重要的函数startActivitySync(),这是一个同步方式启动Activity的功能,在正常的startActivity()之后,一直进入等待状态,直到Activity运行起来该函数才返回,这样,当我们想知道一个Activity的启动性能的时候,这个是非常重要的实现。
public Activity startActivitySync(Intent intent) {
……
getTargetContext().startActivity(intent);
do {
try {
mSync.wait();
} catch (InterruptedException e) {
}
} while (mWaitingActivities.contains(aw));
……
}
余下像性能快照、事件发送等功能就留给大家自己研究了。
最后要说的是对Instrumentation的使用是要实现自己的子类的,并且为我们预留了onCreate()、onStart()等接口,在Android的测试包里也有子类的示例,可以参考。另外别忘了要在AndroidManifest.xml文件中加入 <instrumentation> 标签才行。
——欢迎转载,转载请注明出处,谢谢——