欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载!

大家好,今天想与大家一起分享的是Activity。我们平时接触的最多的就是Activity了,作为四大组件中最为重要的老大,Activity究竟是如何启动的呢?这篇文章将会从源码的角度为大家进行全方位的解析,为了方便大家理解整个的过程,我会用流程图的方式将整个过程串起来,希望对大家有所帮助。

开始吧!

一般我们启动Activity有两种方法,这里我就不再详细说这两种方法的用法了,不过他们都是调用了同样的一个逻辑startActivity。所以我们分析Activity的启动流程就从这个方法开始。

 public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}

可以看到尽管startActivity()有多种重载方式,但是最终调用的还是startActivityForResult,所以我们只需要看startActivityForResult里面的实现逻辑即可。这里需要注意的一点就是调用了startActivityForResult方法时传入的一个参数为-1,为什么是-1呢?还记得我们如果需要下一个Activity返回数据给目前这个Activity的时候都是调用startActivityForResult方法,不会去调用startActivity,因为startActivity尽管最后还是调用startActivityForResult,但是他设置了requestCode参数为-1,二在startActivityForResult方法中会判断requestCode是否大于等于0,如果小于0就不会返回结果,因此我们都会选择startActivityForResult方法以取回结果,并且设置其code参数大于等于0。下面我们来看看startActivityForResult的实现:

public void startActivityForResult(
@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
//mParent是一个Activity对象,表示该Activity是否由父Activity启动
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
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());
}
//这里就是判断requestCode的逻辑
if (requestCode >= 0) {
mStartedActivity = true;
} cancelInputsAndStartExitTransition(options);
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}

在startActivityForResult方法中,首先会判断该Activity是否由父Activity启动,即mParent,如果他是第一个Activity,就会调用Instrumentation的execStartActivity方法,这里再看一下判断requestCode的逻辑:

if (requestCode >= 0) {
mStartedActivity = true;
}

可以看到在这里确实判断了requestCode的大小,大于等于0的时候才会返回结果,否则是不会的。

继续说回execStartActivity方法,这里就是正真执行Activity启动的操作,解释一下他的几个参数:

  • this,为启动Activity的对象
  • mMainThread.getApplicationThread(),为Binder对象,是主进程的context对象
  • token,也是一个Binder对象,指向了服务端一个ActivityRecord对象
  • target,为启动的Activity
  • intent,启动的Intent对象
  • requestCode,请求码
  • options,参数

这里的第一个Binder对象在我们的整个分析过程中将扮演者非常重要的作用,如果你对Binder不熟悉的话,请到这里了解有关Binder机制的内容。

接下来是execStartActivity方法:

public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}

这里最重要的就是调用了ActivityManagerNative.getDefault().startActivity(),但是ActivityManagerNative.getDefault()是什么东西呢?我们继续看getDefault()的源码:

static public IActivityManager getDefault() {
return gDefault.get();
} private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
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;
}
};

可以看到其中声明了一个Singleton封装类,其类型是IActivityManager,注意到其中调用了asInterface方法,接着看他做了什么?

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);
} //ActivityManagerProxy:startActivity
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.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;
}

可以看到asInterface返回了一个ActivityManagerProxy对象,也就是说ActivityManagerNative.getDefault()返回的就是一个ActivityManagerProxy对象,通过之前的BInder机制的文章我们可以知道Proxy是运行在客户端的,客户端通过将参数写入Proxy类,接着Proxy就会通过Binder去远程调用服务端的具体方法,因此,我们只是借用ActivityManagerProxy来调用ActivityManagerService的方法,他们之间的关系如下所示:



到目前为止Activity的启动流程就是如下所示了,可以看到Activity的启动逻辑来到了AMS中。

在AMS中启动Activity

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, options,
UserHandle.getCallingUserId());
} @Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, options, false, userId, null, null);
}

在startActivity中直接调用了startActivityAsUser方法,而在startActivityAsUser中则是调用mStackSupervisor.startActivityMayWait方法:

final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
ActivityContainer container, TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS; ...
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask); ...
return err;
}

这个方法中主要构造了ActivityManagerService端的Activity对象:ActivityRecord,并根据Activity的启动模式执行了相关逻辑。然后调用了startActivityUncheckedLocked方法,而在startActivityUncheckedLocked中则调用了startActivityUncheckedLocked方法,startActivityUncheckedLocked方法则会调用startActivityLocked方法,startActivityLocked又会调用resumeTopActivitiesLocked方法,其最后调用了resumeTopActivityLocked方法。

经过一系列的调用之后,最终来到了startPausingLocked方法,它会执行Activity的onPause方法,从而结束当前的Activity。

首先来看startPausingLocked方法:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,boolean dontWait) {
...
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
...
}

这里有一个很重要的地方就是prev.app.thread,其实他就是一个IApplicationThread类型的对象,而ApplicationThread则是ActivityThread的一个内部类,它继承了IApplicationThread,并且都是Binder对象,所以说Appcation是一个客户端,而ActivityThread中是一个服务端,到现在为止,Activity的调用来到了ActivityThread中,如下图所示:

在ActivityThread中pause掉当前Activity

在ActivityThread中则是调用了schedulePauseActivity来执行pause操作:

public final void schedulePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport) {
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
configChanges);
}

可以看到在schedulePauseActivity中则是通过handler来发送消息,消息类型为PAUSE_ACTIVITY_FINISHING,那接下来就应该看收到消息之后如何来处理了,

private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
if (userLeaving) {
performUserLeavingActivity(r);
} r.activity.mConfigChangeFlags |= configChanges;
performPauseActivity(token, finished, r.isPreHoneycomb()); // Make sure any pending writes are now committed.
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
} // Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
}
mSomeActivitiesChanged = true;
}
}

可以看到在方法内部通过调用performPauseActivity方法来实现对当前Activity的onPause生命周期方法的回调,具体是调用了performPause方法:

final void performPause() {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
mResumed = false;
}

可以看到最终是调用了Activity的onPause()方法,接着我们回到handlePauseActivity的第二个方法ActivityManagerNative.getDefault().activityPaused(token),这是应用进程告诉服务进程,当前的Activity已经执行完成onPause方法了,其最后会调用completePauseLocked方法:

private void completePauseLocked(boolean resumeNext) {
...
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDown()) {
mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked(null);
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run,
// do resume anyway to start something. Also if the top
// activity on the stack is not the just paused activity,
// we need to go ahead and resume it to ensure we complete
// an in-flight app switch.
mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
}
}
}
}

可以看到经过了一系列的逻辑之后,又调用了resumeTopActivitiesLocked方法,而在该方法中则是调用了startSpecificActivityLocked 来启动新的Activity。来看看目前的流程图:

启动新的Activity

在startSpecificActivityLocked方法中,其实现细节则是和调用Activity的pause方法一样,都是通过Handler机制,发送一个启动Activity的消息,接着处理该消息最后启动Activity。其调用的是performLaunchActivity方法:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
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);
r.intent.prepareToEnterProcess();
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.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
...
return activity;
}

可以看到最终的Activity对象终于创建出来了,可以看到其过程是使用反射机制创建的,而反射机制在Android系统中的应用也是随处可见。在接下来的过程中还会继续执行Activity的onCreate等一系列的生命周期方法。

最后再来看一下整个过程最终的流程图:

从源码的角度看Activity是如何启动的的更多相关文章

  1. 从源码的角度看Service是如何启动的

    欢迎访问我的个人博客 ,原文链接:http://wensibo.top/2017/07/16/service/ ,未经允许不得转载! 七月中旬了,大家的实习有着落了吗?秋招又准备的怎么样了呢?我依旧在 ...

  2. 从源码的角度看 React JS 中批量更新 State 的策略(下)

    这篇文章我们继续从源码的角度学习 React JS 中的批量更新 State 的策略,供我们继续深入学习研究 React 之用. 前置文章列表 深入理解 React JS 中的 setState 从源 ...

  3. 从源码的角度看 React JS 中批量更新 State 的策略(上)

    在之前的文章「深入理解 React JS 中的 setState」与 「从源码的角度再看 React JS 中的 setState」 中,我们分别看到了 React JS 中 setState 的异步 ...

  4. 从源码的角度再看 React JS 中的 setState

    在这一篇文章中,我们从源码的角度再次理解下 setState 的更新机制,供深入研究学习之用. 在上一篇手记「深入理解 React JS 中的 setState」中,我们简单地理解了 React 中 ...

  5. [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...

  6. 从源码的角度解析View的事件分发

    有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图 ...

  7. Android AsyncTask完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...

  8. 从源码的角度分析ViewGruop的事件分发

    从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...

  9. 第九节:从源码的角度分析MVC中的一些特性及其用法

    一. 前世今生 乍眼一看,该标题写的有点煽情,最近也是在不断反思,怎么能把博客写好,让人能读下去,通俗易懂,深入浅出. 接下来几个章节都是围绕框架本身提供特性展开,有MVC程序集提供的,也有其它程序集 ...

随机推荐

  1. Unity中提升像素字体清晰度

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Unity5.6.0f3 Unity UI系统是非常好的,但默认情况下,使用像像素艺术风格游戏那样需要非常锋利的边框的字体 ...

  2. 开涛spring3(7.2) - 对JDBC的支持 之 7.2 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  3. An Introduction to Stock Market Data Analysis with R (Part 1)

    Around September of 2016 I wrote two articles on using Python for accessing, visualizing, and evalua ...

  4. ASP.NET Core:使用EntityFrameworkCore操作MySql来丰富仓储模块

    概述 上一篇简单介绍了Dapper的基本用法,数据的存储为SqlServer.那么这一篇就记录一下使用EFCore来操作MySql的一些方式,这种模式比较适合那种一个项目中需要操作多种数据库的模式.不 ...

  5. centos7.2下编译安装apache2.4

    1.安装编译工具 [root@carl httpd-2.4.25]# yum groupinstall 'Development Tools' 'Server Platform Development ...

  6. Boosting决策树:GBDT

    GBDT (Gradient Boosting Decision Tree)属于集成学习中的Boosting流派,迭代地训练基学习器 (base learner),当前基学习器依赖于上一轮基学习器的学 ...

  7. 小K的H5之旅-实战篇(一)

    一.前言 本K在经过两个星期的html和css学习之后,第一次去尝试完成一个网站主页的制作.在四天之后,本K也终于完成了杰瑞教育主页的html和css部分,至于部分涉及js的部分,因为本K还没有学习过 ...

  8. 初识Java-IO流

    1.定义: 流是一种抽象概念,它代表了数据的无结构化传递.数据流(Stream)是指数据通信的通道. 2.流的分类: 1)按流向分 输入流:从数据源到程序中的流 输出流:从程序到数据源的流 2)按数据 ...

  9. Python爬虫Dota排行榜爬取

    1.分析网站 打开开发者工具,我们观察到排行榜的数据并没有在doc里 doc文档 在Javascript里我么可以看到下面代码: ajax的post方法异步请求数据 在 XHR一栏里,我们找到所请求的 ...

  10. Blend在WPF开发过程中的作用

    WPF开发时,用VS2012就足够了,因为里面的确有控件拖放编辑和便利的带输入自动完成的xaml编辑器. 但是在需要改变某些控件的样式时,特别是style和template是,看网上搜到的教程,洋洋洒 ...