本文分析Activity的流程图如下,下图是整个Activity启动的方法调用链,主要涉及到的类包括:Activity、Instrumentation、ActivityManagerService、ActivityStackSuper、ActivityStack、ActivityThread、ActivityThread.ApplicationThread,至于其他的ProcessRecord、ActivityRecord、TaskRecord等等等等都忽略不计,首先上一张Activity启动过程的方法调用链:
我们已知要想启动一个Activity的时候直接调用startActivity()或ActivityForResult()方法,实际上startActivity()也是调用了startActivityForResult(),因此,我们从startActivity()开始一步一步的分析。
一、startActivity()的执行过程
首先来看下startActivity()源码:
@Override
public void startActivity(Intent intent) {
startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
可以看到我们客户端在启动一个Activity时最多会涉及相关的四个方法,就是当我们直接调用startActivity()时,通过层层调用最后调用了startActivityForResult(Intent intent, int requestCode, Bundle options)这个方法,下面我们就重点研究这个方法:
先挑简单的说,注意if (requestCode >= 0)判断,当我们调用startActivity()时,默认的requestCode就是-1,所以此时mStartActivity=false,也就是告诉系统当那个被启动的Activity被finish()后前一个Activity不需要收到消息,即onActivityResult()里不会收到任何消息,所以当我们调用startActivityForResult()的时候其requestCode一定要保证大于等于0,否则将不会收到预期效果。
上面简单说了下startActivity()和startActivityForResult()在使用时注意的细节,接下来就说下它到底是怎么启动的。
我们知道在startActivityForResult()中首先对 if (mParent == null)进行判断,这个mParent是什么东东呢?它实际上也是一个Activity实例,现在假设我们要启动的一个Activity是自app安装以来首次启动,那么此时mParent为null,他就会执行以下代码:
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
}
首先执行的就是Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this,mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);看起来比较复杂,我们把它剥开来分析,首先是要执行mInstrumentation.execStartActivity(....),看名字直译过来就是“执行启动Activity”,那么mInstrumentation参数是哪里来的呢?什么时候被赋值的呢?我们先不急,先看下execStartActivity()中一个比较重要的参数就是mMainThread.getApplicationThread(),那么这个mMainThread又是从哪里来的呢?什么时候被赋值的呢?其实我们在Activity源码里可以找到蛛丝马迹,mInstrumentation和mMainThread都是在Activity的attach()方法中被赋值的,mMainThread也就是整个app的主线程(UI线程),这个是本文稍后的重点讲解,而mInstrumentation就是一个Instrumentation实例,Instrumentation按照其源码注释的意思就是:
/**
* Base class for implementing application instrumentation code. When running
* with instrumentation turned on, this class will be instantiated for you
* before any of the application code, allowing you to monitor all of the
* interaction the system has with the application. An Instrumentation
* implementation is described to the system through an AndroidManifest.xml's
* tag.
*/
其大意就是这是为实现应用“应用仪表”代码的基类(这么翻译好拗口啊。。),当用这个仪表打开时,这个类会在我们应用的所有代码之前被实例化,允许我们监督所有的系统和本应用之间的交互,对于Instrumentaion的实现,我们需要在AndroidMainfest.xml文件里添加描述。-----以上是直接翻译过来的,用我们的话来说,这个类呢就是用来监督别人的,这种手段用在单元测试方面比较多。
上面说了那么多废话,话说回来我们该看看attach()方法了。以下便是源码:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
mFragments.attachActivity(this);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
对于attach(),就以前的知识范围来讲与其说Activity的onCreate()方法是app的入口,倒不如说attach()是app的入口(当然这里只是突出attach的地位,并不是说attach就是app的入口,如果硬要讨论程序的入口,依次往上推就是Application的onCreate、ActivityThread的main()、Linux的init()了)。其实仔细看attach()方法就是一个赋值的过程,下面我们来具体看下:
首先是attachBaseContext(context);这个赋值就是一个Activity的上下文赋值,他就是给ContextWrapper的Context对象的mBase变量赋值。然后就是mFragments.attachActivity(this);这个mFragments是一个FragmentManagerImp实例,它执行的结果就是将Fragment和Activity联系起来。接下来就是mWindow的创建,他实际上就是一个PhoneWindow实例,关于此实例详见我的另一篇博文View的绘制过程 ,然后就是一系列的赋值了,这里这出赋值清单如下:
ActivityThread mMainThread = aThread; //在这里赋值主线程
Instrumentation mInstrumentation = instr;
IBinder mToken = token;
int mIdent = ident;
Application mApplication = application;
Intent mIntent = intent;
ComponentName mComponent = intent.getComponent();
ActivityInfo mActivityInfo = info;
CharSequence mTitle = title;
Activity mParent = parent; //就是在这里赋值mParent
String mEmbeddedID = id;
NonConfigurationInstances mLastNonConfigurationInstances = lastNonConfigurationInstances;
好了,那么我们知道了主线程实例以及Application实例、IBinder实现都是在attach()中赋值的,那么attach()方法是在什么时候被调用的呢?答案就是:attach()在ActivityThread中调用。那么问题来了,第一个入口Activity是在什么时候调用的呢?这就涉及到APK的启动过程了,这篇文章详细看APK的启动过程分析 。好了,现在我们回到mInstrumentation.execStartActivity(this,mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);这个方法的调用上来,首先来看看mMainThread.getApplicationThread(),这个是ActivityThread中的方法,用来获取ApplicationThread的,其实getApplicationThread()方法就直接returnmAppThread ,并无其他操作,mApplicationThread也是在ActivityThread中作为全局变量直接创建的final ApplicationThread mAppThread = new ApplicationThread();
好了,接下来就看看mInstruction.execStartActivity()方法吧,此方法当然是在Instructation()里了,源码如下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Fragment target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mWho : null,
requestCode, 0, null, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
可以看到,该方法的第二个参数是IBinder,但是我们在Activity中调用mInstrumentation他的时候传递的是一各ApplicationThread对象,为什么可以从ApplicationThread强转成IBinder呢?因为ApplicationThread是继承ApplicationThreadNative,此类实现了Binder,Binder实现了IBinder接口,就是这么回事!接着看,IBinder实例contextThread(ApplicationThread对象)又被强转成了IApplicationThread对象,为何可以这么任性的转?因为AplicationThreadNative不紧继承了Binder类还实现了IApplicationThread接口,就是这么回事!不懂的可以点击看下Binder详解!好,继续往下看ActivityManagerNative.getDefault().startActivity(...)此方法是启动一个Activity的核心代码,ActivityManagerNative.getDefault()返回的是一个IActivityManager接口实例,它是由ActivityManagerProxy实现的。我们直接去看ActivityManagerProxy的startActivity()吧:
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, String profileFile,
ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
data.writeString(profileFile);
if (profileFd != null) {
data.writeInt(1);
profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
此startActivity()方法主要就是通过Binder机制完成了客户端向服务器端的通信,即调用mRemote.transact()方法完成通信,那么
这个ActivityManagerProxy的mRemote实例是在什么时候赋值的呢?这就涉及到android.util包下的一个Singleton类了,上面我们说到在
mInstruction.execStartActivity()方法中ActivityManagerNative.getDefault().startActivity(...)是关键,此处的getDefault()方法虽然只做了一件事,那就是返回一个IActivityManager实例:
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}
虽然上面的代码很简单,但却是很关键的,首先我们看下gDefault是个什么对象以及怎么创建的:
private static final Singleton gDefault = new Singleton() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
也许你会问,gDefault是一个Singleton类实例,此处直接创建的gDefault实例时重写了其create()方法,但是在调用get()方法时是如何获取到IActivityManager实例的呢?我们来看下Singleton类的源码,他是一个抽象类,就两个方法,一个get()一个onCreate():
/**
* Singleton helper class for lazily initialization.
*
* Modeled after frameworks/base/include/utils/Singleton.h
*
* @hide
*/
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
看代码就一目了然,原来我们在
调用ActivityManagerNative.getDefault()时,Singleton的get()方法如果检查到其实例为空就会去执行create()方法并返回,此时就会调用到创建gDefault对象时重写的onCreate()方法,此方法就是重中之重了,正如上面的代码所示,他会先 执行 IBinder b = ServiceManager.getService("activity");获取一个IBinder实例,至于ServiceManager如何通过getService()获取IBinder实例这不是我们的重点讨论。然后就调用ActivityThreadNative方法的asInterface()方法:IActivityManager am = asInterface(b);注意此时这个b是一个IBinder实例,接下来我们看下asInterface()做了什么事情:
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
asInterface()方法在必要的情况下会创建一个代理,也就是ActivityManagerProxy,在创建此代理时传递了一个IBinder实例进去,去他的构造方法看会发现,
此obj直接赋值给了mRemote,至此mRemote对象赋值完毕,那么客户端通过 mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);告诉服务端要启动一个Activity,然后就进入AMS进程了,在服务端的AMS进程中经过一系列的调用,最后回到ActivityThread.ApplicationThread的调用流程了。接下来就该ActivityThread闪亮登场了,客户端已经向服务端请求了要启动一个Activity,并且服务端AMS等已经完成一系列的任务栈创建等工作,然后AMS说让ActivityThread来完成真正的Activity启动,然后ActivityThread就开始要准备启动一个Activity了,实际上在执行ApplicationThreadProxy的schedulePauseActivity()方法时,就是在用IPC原理远程调用ApplicationThread的schedulePauseActivity()方法,其实经过ActivityThread的内部类H(就是一个Handler),最后一步步调用到了handleLaunchActivity()方法,我们看下此类源码:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
if (r.profileFd != null) {
mProfiler.setProfiler(r.profileFile, r.profileFd);
mProfiler.startProfiling();
mProfiler.autoStopProfiler = r.autoStopProfiler;
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
//看这里,此处就生产了一个Activity实例
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out
// paused, because it needs to be visible but isn't in the
// foreground. We accomplish this by going through the
// normal startup (because activities expect to go through
// onResume() the first time they run, before their window
// is displayed), and then pausing it. However, in this case
// we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just
// retain the current state it has.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// We need to keep around the original state, in case
// we need to be created again. But we only do this
// for pre-Honeycomb apps, which always save their state
// when pausing, so we can not have them save their state
// when restarting from a paused state. For HC and later,
// we want to (and can) let the state be saved as the normal
// part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null);
} catch (RemoteException ex) {
// Ignore
}
}
}
对于上面的方法,我们直接看重点performLaunchActivity()这个方法的调用,因为正是该方法生成了一个Activity实例,接下来我们看下该方法是如何完成Activity的创建的:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
看起来此方法比较长啊有木有,我们只看关键的,因为我们现在只关心Activity实例的创建!不关心其他的特性!~ ~!所以呢我这里选取一个最重要的一部分拿出来:
Activity activity = null;
try {
//注意,这个r.packageInfo是一个LoadedApk实例,
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
可以看到生成Activity实例的代码又糊掉了Instrumentation里去了,我们去看看该类的newActivity():
/**
* Perform instantiation of the process's {@link Activity} object. The
* default implementation provides the normal system behavior.
*
* @param cl The ClassLoader with which to instantiate the object.
* @param className The name of the class implementing the Activity
* object.
* @param intent The Intent object that specified the activity class being
* instantiated.
*
* @return The newly instantiated Activity object.
*/
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
从上可以看出来,一个Activity的实例是被反射出来的,而不是new出来的T_T,以后有人问Activity实例时怎么创建的,你就回答是系统反射出来的好了,哈哈~。以上说了那么多,其实最关键的是客户端如何通知服务端来进行Activity启动,这种通信机制后面会另外开一片文章说道。
以上说了半天Activity的诞生,都是源于Instrumentmentation的execStartActivity()的int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mWho : null,
requestCode, 0, null, null, options);的执行,分析完之后发现他还返回了一个参数,这个参数有什么用呢?当然有用了,接下来会调用方法来对Activity启动的结构进行告知用户,如果启动出问题了就报异常,启动成功就成功吧:
/*package*/ static void checkStartActivityResult(int res, Object intent) {
//如果启动成功直接return掉
if (res >= ActivityManager.START_SUCCESS) {
return;
}
//开始报一系列异常
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
//新手最熟悉这种异常吧。。通常忘记在AndroidMainfest.xml文件中添加Activity描述时会异常
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
最后贴出一张关于ApplicationThread的关系图,此图参考http://blog.csdn.net/myarrow/article/details/14223493这位兄弟的博客。我觉得这张图画得和本博客得思路讲解一致,故拿过来贴在此处,本人就懒得去画啦~
好了,关于Activity的启动方式我们已经说完了,下一篇文章就说说Activity启动的四种模式和Activity栈吧!总的来说,在ActivityThread中一个Activity被启动时相关方法调用层次时酱紫的:schedule->handle->perform->activity/Insturmation。