源码解析StartActivity的过程

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. /*package*/ static void checkStartActivityResult(int res, Object intent) {

  2. if (res >= ActivityManager.START_SUCCESS) {

  3. return;

  4. }

  5. switch (res) {

  6. case ActivityManager.START_INTENT_NOT_RESOLVED:

  7. case ActivityManager.START_CLASS_NOT_FOUND:

  8. if (intent instanceof Intent && ((Intent)intent).getComponent() != null)

  9. throw new ActivityNotFoundException(

  10. "Unable to find explicit activity class "

  11. + ((Intent)intent).getComponent().toShortString()

  12. + “; have you declared this activity in your AndroidManifest.xml?”);

  13. throw new ActivityNotFoundException(

  14. "No Activity found to handle " + intent);

  15. case ActivityManager.START_PERMISSION_DENIED:

  16. throw new SecurityException("Not allowed to start activity "

  17. + intent);

  18. case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:

  19. throw new AndroidRuntimeException(

  20. “FORWARD_RESULT_FLAG used while also requesting a result”);

  21. case ActivityManager.START_NOT_ACTIVITY:

  22. throw new IllegalArgumentException(

  23. “PendingIntent is not an activity”);

  24. default:

  25. throw new AndroidRuntimeException("Unknown error code "

  26. + res + " when starting " + intent);

  27. }

  28. }

接下来我们要去看看IApplicationThread,因为核心功能由其内部的scheduleLaunchActivity方法来完成,由于IApplicationThread是个接口,所以,我们需要找到它的实现类,我已经帮大家找到了,它就是ActivityThread中的内部类ApplicationThread,看下它的继承关系:

private class ApplicationThread extends ApplicationThreadNative;

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;

可以发现,ApplicationThread还是间接实现了IApplicationThread接口,先看下这个类的结构

看完ApplicationThread的大致结构,我们应该能够猜测到,Activity的生命周期中的resume、newIntent、pause、stop等事件都是由它触发的,事实上,的确是这样的。这里,我们为了说明问题,仅仅看scheduleLaunchActivity方法

code:ApplicationThread#scheduleLaunchActivity

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,

  2. ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,

  3. int procState, Bundle state, List pendingResults,

  4. List pendingNewIntents, boolean notResumed, boolean isForward,

  5. String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {

  6. updateProcessState(procState, false);

  7. ActivityClientRecord r = new ActivityClientRecord();

  8. r.token = token;

  9. r.ident = ident;

  10. r.intent = intent;

  11. r.activityInfo = info;

  12. r.compatInfo = compatInfo;

  13. r.state = state;

  14. r.pendingResults = pendingResults;

  15. r.pendingIntents = pendingNewIntents;

  16. r.startsNotResumed = notResumed;

  17. r.isForward = isForward;

  18. r.profileFile = profileName;

  19. r.profileFd = profileFd;

  20. r.autoStopProfiler = autoStopProfiler;

  21. updatePendingConfiguration(curConfig);

  22. queueOrSendMessage(H.LAUNCH_ACTIVITY, r);

  23. }

说明:上述代码很好理解,构造一个activity记录,然后发送一个消息,所以,我们要看看Handler是如何处理这个消息的,现在转到这个Handler,它有个很短的名字叫做H

code:ActivityThread#H

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. //这个类太长,我只帖出了我们用到的部分

  2. private class H extends Handler {

  3. public void handleMessage(Message msg) {

  4. if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));

  5. switch (msg.what) {

  6. //这里处理LAUNCH_ACTIVITY消息类型

  7. case LAUNCH_ACTIVITY: {

  8. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);

  9. ActivityClientRecord r = (ActivityClientRecord)msg.obj;

  10. r.packageInfo = getPackageInfoNoCheck(

  11. r.activityInfo.applicationInfo, r.compatInfo);

  12. //这里处理startActivity消息

  13. handleLaunchActivity(r, null);

  14. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

  15. } break;

  16. case RELAUNCH_ACTIVITY: {

  17. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityRestart”);

  18. ActivityClientRecord r = (ActivityClientRecord)msg.obj;

  19. handleRelaunchActivity®;

  20. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

  21. } break;

  22. case PAUSE_ACTIVITY:

  23. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityPause”);

  24. handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);

  25. maybeSnapshot();

  26. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

  27. break;

  28. }

  29. }

说明:看来还要看handleLaunchActivity

code:ActivityThread#handleLaunchActivity

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

  2. // If we are getting ready to gc after going to the background, well

  3. // we are back active so skip it.

  4. unscheduleGcIdler();

  5. if (r.profileFd != null) {

  6. mProfiler.setProfiler(r.profileFile, r.profileFd);

  7. mProfiler.startProfiling();

  8. mProfiler.autoStopProfiler = r.autoStopProfiler;

  9. }

  10. // Make sure we are running with the most recent config.

  11. handleConfigurationChanged(null, null);

  12. if (localLOGV) Slog.v(

  13. TAG, "Handling launch of " + r);

  14. //终于到底了,大家都有点不耐烦了吧,从方法名可以看出,

  15. //performLaunchActivity真正完成了activity的调起,

  16. //同时activity会被实例化,并且onCreate会被调用

  17. Activity a = performLaunchActivity(r, customIntent);

  18. if (a != null) {

  19. r.createdConfig = new Configuration(mConfiguration);

  20. Bundle oldState = r.state;

  21. //看到没,目标activity的onResume会被调用

  22. handleResumeActivity(r.token, false, r.isForward,

  23. !r.activity.mFinished && !r.startsNotResumed);

  24. if (!r.activity.mFinished && r.startsNotResumed) {

  25. // The activity manager actually wants this one to start out

  26. // paused, because it needs to be visible but isn’t in the

  27. // foreground.  We accomplish this by going through the

  28. // normal startup (because activities expect to go through

  29. // onResume() the first time they run, before their window

  30. // is displayed), and then pausing it.  However, in this case

  31. // we do -not- need to do the full pause cycle (of freezing

  32. // and such) because the activity manager assumes it can just

  33. // retain the current state it has.

  34. try {

  35. r.activity.mCalled = false;

  36. //同时,由于新activity被调起了,原activity的onPause会被调用

  37. mInstrumentation.callActivityOnPause(r.activity);

  38. // We need to keep around the original state, in case

  39. // we need to be created again.  But we only do this

  40. // for pre-Honeycomb apps, which always save their state

  41. // when pausing, so we can not have them save their state

  42. // when restarting from a paused state.  For HC and later,

  43. // we want to (and can) let the state be saved as the normal

  44. // part of stopping the activity.

  45. if (r.isPreHoneycomb()) {

  46. r.state = oldState;

  47. }

  48. if (!r.activity.mCalled) {

  49. throw new SuperNotCalledException(

  50. "Activity " + r.intent.getComponent().toShortString() +

  51. " did not call through to super.onPause()");

  52. }

  53. } catch (SuperNotCalledException e) {

  54. throw e;

  55. } catch (Exception e) {

  56. if (!mInstrumentation.onException(r.activity, e)) {

  57. throw new RuntimeException(

  58. "Unable to pause activity "

  59. + r.intent.getComponent().toShortString()

  60. + ": " + e.toString(), e);

  61. }

  62. }

  63. r.paused = true;

  64. }

  65. } else {

  66. // If there was an error, for any reason, tell the activity

  67. // manager to stop us.

  68. try {

  69. ActivityManagerNative.getDefault()

  70. .finishActivity(r.token, Activity.RESULT_CANCELED, null);

  71. } catch (RemoteException ex) {

  72. // Ignore

  73. }

  74. }

  75. }

说明:关于原activity和新activity之间的状态同步,如果大家感兴趣可以自己研究下,因为逻辑太复杂,我没法把所有问题都说清楚,否则就太深入细节而淹没了整体逻辑,研究源码要的就是清楚整体逻辑。下面看最后一个方法,这个方法是activity的启动过程的真正实现。

code:ActivityThread#performLaunchActivity

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

  2. // System.out.println(“##### [” + System.currentTimeMillis() + “] ActivityThread.performLaunchActivity(” + r + “)”);

  3. ActivityInfo aInfo = r.activityInfo;

  4. if (r.packageInfo == null) {

  5. r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,

  6. Context.CONTEXT_INCLUDE_CODE);

  7. }

  8. //首先从intent中解析出目标activity的启动参数

  9. ComponentName component = r.intent.getComponent();

  10. if (component == null) {

  11. component = r.intent.resolveActivity(

  12. mInitialApplication.getPackageManager());

  13. r.intent.setComponent(component);

  14. }

  15. if (r.activityInfo.targetActivity != null) {

  16. component = new ComponentName(r.activityInfo.packageName,

  17. r.activityInfo.targetActivity);

  18. }

  19. Activity activity = null;

  20. try {

  21. java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

  22. //用ClassLoader(类加载器)将目标activity的类通过类名加载进来并调用newInstance来实例化一个对象

  23. //其实就是通过Activity的无参构造方法来new一个对象,对象就是在这里new出来的。

  24. activity = mInstrumentation.newActivity(

  25. cl, component.getClassName(), r.intent);

  26. StrictMode.incrementExpectedActivityCount(activity.getClass());

  27. r.intent.setExtrasClassLoader(cl);

  28. if (r.state != null) {

  29. r.state.setClassLoader(cl);

  30. }

  31. } catch (Exception e) {

  32. if (!mInstrumentation.onException(activity, e)) {

  33. throw new RuntimeException(

  34. "Unable to instantiate activity " + component

  35. + ": " + e.toString(), e);

  36. }

  37. }

  38. try {

  39. Application app = r.packageInfo.makeApplication(false, mInstrumentation);

  40. if (localLOGV) Slog.v(TAG, "Performing launch of " + r);

  41. if (localLOGV) Slog.v(

  42. TAG, r + “: app=” + app

  43. + “, appName=” + app.getPackageName()

  44. + “, pkg=” + r.packageInfo.getPackageName()

  45. + “, comp=” + r.intent.getComponent().toShortString()

  46. + “, dir=” + r.packageInfo.getAppDir());

  47. if (activity != null) {

  48. Context appContext = createBaseContextForActivity(r, activity);

  49. CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());

  50. Configuration config = new Configuration(mCompatConfiguration);

  51. if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "

  52. + r.activityInfo.name + " with config " + config);

  53. activity.attach(appContext, this, getInstrumentation(), r.token,

  54. r.ident, app, r.intent, r.activityInfo, title, r.parent,

  55. r.embeddedID, r.lastNonConfigurationInstances, config);

  56. if (customIntent != null) {

  57. activity.mIntent = customIntent;

  58. }

  59. r.lastNonConfigurationInstances = null;

  60. activity.mStartedActivity = false;

  61. int theme = r.activityInfo.getThemeResource()

  62. if (theme != 0) {

尾声

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Android核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、热修复设计、插件化框架解读、组件化框架设计、图片加载框架、网络、设计模式、设计思想与代码质量优化、程序性能优化、开发效率优化、设计模式、负载均衡、算法、数据结构、高级UI晋升、Framework内核解析、Android组件内核等。

不仅有学习文档,视频+笔记提高学习效率,还能稳固你的知识,形成良好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!

image

大厂面试真题

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《2017-2021字节跳动Android面试历年真题解析》

好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

[外链图片转存中…(img-dcYiNXzr-1726046011798)]

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!

[外链图片转存中…(img-Y6VR4VKW-1726046011799)]

大厂面试真题

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-TIxvrfLH-1726046011799)]

《2017-2021字节跳动Android面试历年真题解析》

[外链图片转存中…(img-Jh26HkJm-1726046011799)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值