Android8.0源码解析——Activity的启动过程

2024-08-29 14:58

本文主要是介绍Android8.0源码解析——Activity的启动过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Activity是Android的四大组件,关于Activity 的启动过程是怎么样的昵,下面我们主要通过Android8.0的源码来分析一下。

1、Activity的生命周期:

Activity的生命周期我们都知道有
protected void onCreate(); 
protected void onRestart(); 
protected void onStart(); 
protected void onResume(); 
protected void onPause(); 
protected void onStop(); 
protected void onDestory(); 

2、Activity的启动模式

activity启动时可以设置不同的启动模式,主要是:standrand,singleTop,singleTask,instance等四种启动模式,不同的启动模式在启动Activity时会执行不同的逻辑,系统会按不同的启动模式将Activity存放到不同的activity栈中。 
关于Activity启动模式的详细介绍,可以参考: 

3、Activity的启动进程

通常情况下,一个应用只有一个进程,这个进程就是应用的包名,如果在AndroidManifest.xml中定义Activity时没有指定android:process属性,那么该activity所在的进程就是应用默认的进程(进程名称为包名的进程),我们在AndroidManifest.xml文件中设定activity 的android:process属性来指定activity的启动进程,当activity 启动时首先会检测当前Activity的所属进程启动没,如果没有启动,则先启动该Activity的所属进程,进程启动之后再执行Activity的启动。

4、Intent 启动 Activity

Intent启动Activity的方式有两种,分为显式启动和隐式启动,我们最常用的startactivity就是显式启动,显式启动就是在初始化Intent的时候直接调用需要启动Activity的字节码,显示启动的好处就是:告诉Intent对象将要启动的Activity对象,不需要执行intent filter搜索需要启动哪个Activity,但是显示启动不能启动其他应用的Activity(由于无法获取其他应用Activity的字节码),启动其他应用的Activity需要用隐式启动。

5、Activity启动源码分析

1、从Activity到ActivityManagerService。

我们启动Activity启动时,首先从Activity源码会请求调用ActivityManagerService中的方法,大致流程如下图所示:

一、 首先我们在Activity中调用startActivity(intent)时会执行下面的方法。
@Override
public void startActivity(Intent intent) {this.startActivity(intent, null);
}
上面的方法会调用下面的方法。由于传入的options参数是null 所以会执行startActivityForResult(intent ,-1);
@Override
public void startActivity(Intent intent, @Nullable 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);}
}
由于在上一步中我们传入的options是null所以我们执行startActivityForResult(intent,-1);
在这里我们会发现startActivity最终调用的还是startActivityForResult方法,细心的读者会想“ startActivity最终调用的还是startActivityForResult方法,那么为什么我们在Activity调用startActivity不可以在Activity中会调用onActivityResult,而调用startActivityForResult时可以回调onActivityResult? "
我们继续往下看代码,看完这个 startActivityForResult 的源码就知道了
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);
}
上面的方法又会调用下面的 startActivityForResult 方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {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());}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;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} 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所以mParent值为空,所以会执行if分支,原来在第13行会判断returnCode是否大于0,如果大于0, mStartedActivity 置为true, 只有当它为true时才会在Activity中回调onActivityResult 。通过前面的代码我们发现,由于我们之前在Activity中调用 startActivity 后最终调用 startActivityForResult 时传入的 returnCode 为-1,所以才不会回调 onActivityResult

上面我们看由于mParent为空,所以执行 mInstrumentation.execStartActivity方法,这里的 mInstrumentation Instrumentation 的一个对象, Instrumentation 是Android系统中启动Activity的一个实际操作类,即:Activity 在Application的进程端的启动实际都是由Instrumentation执行的。由于Activity的启动分为Application进程端的启动和SystemService端的启动,所以这里才说是Application进程端的启动是由Instrumentation执行的,下面我们来看下它的 execStartActivity 方法的源码:
 /*** <p>This method throws {@link android.content.ActivityNotFoundException}* if there was no Activity found to run the given Intent.** @param who The Context from which the activity is being started.(Activity对象)* @param contextThread The main thread of the Context from which the activity*                      is being started.(Binder对象,是主进程的context对象)* @param token Internal token identifying to the system who is starting *              the activity; may be null.(也是一个Binder对象,指向了服务端一个ActivityRecord对象)* @param target Which activity is performing the start (and thus receiving *               any result); may be null if this call is not being made*               from an activity.(为启动的Activity)* @param intent The actual Intent to start.(启动的Intent对象)* @param requestCode Identifier for this request's result; less than zero *                    if the caller is not expecting a result.(请求码)* @param options Addition options.(参数)** @return To force the return of a particular result, return an *         ActivityResult object containing the desired data; otherwise*         return null.  The default implementation always returns null.** @throws android.content.ActivityNotFoundException** @see Activity#startActivity(Intent)* @see Activity#startActivityForResult(Intent, int)* @see Activity#startActivityFromChild** {@hide}*/
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {IApplicationThread whoThread = (IApplicationThread) contextThread;Uri referrer = target != null ? target.onProvideReferrer() : null;if (referrer != null) {intent.putExtra(Intent.EXTRA_REFERRER, referrer);}......try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess(who);int result = ActivityManager.getService().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;
}
在这个方法中我们发现主要调用了 ActivityManager.getService().startActivity() 方法,那么ActivityManager.getService()又是啥昵?我们来看下 源码:
public static IActivityManager getService() {return IActivityManagerSingleton.get();
}
what???返回的是IActivityManagerSingleton.get();那IActivityManagerSingleton又是个什么鬼东东?我们继续往下看源码:
private static final Singleton<IActivityManager> IActivityManagerSingleton =new Singleton<IActivityManager>() {@Overrideprotected IActivityManager create() {final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);final IActivityManager am = IActivityManager.Stub.asInterface(b);return am;}};
我们发现它返回的是 IActivityManager.Stub.asInterface (b);我们都知道 Stub 是AIDL(Android Interface Definition Language)生成的 一个Binder类 ,当客户端和服务端要跨进程走transact过程时,它的逻辑就时有Stub的内部类Proxy来代理的。而 asInterdace ()方法的作用是: 将服务端的Binder对象转换为客户端所需要的AIDL接口类型。如果客户端和服务端在同一个进程他返回的就是服务端Stub对象本身,否则他返回的就是系统封装后的Stub.proxy对象。
下面我们来看下 IActivityManager.Stub.asInterface 到底是啥?其实我们发现 ActivityManagerService继承自IActivityManager.Stub ,所以上面返回的就是一个ActivityManagerService对象。
public class ActivityManagerService extends IActivityManager.Stubimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
}

2、从ActivityManagerService 到ApplicationThread

所以 ActivityManager.getService().startActivity() 执行的是ActivityManagerService中的 startActivity 方法,
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,resultWho, requestCode, startFlags, profilerInfo, bOptions,UserHandle.getCallingUserId());
}
这里有调用了 startActivityAsUser 方法,我们继续往下看它的源码:
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {enforceNotIsolatedCaller("startActivity");userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),userId, false, ALLOW_FULL_ONLY, "startActivity", null);// TODO: Switch to user app stacks here.return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,profilerInfo, null, null, bOptions, false, userId, null, null,"startActivityAsUser");
}
这里返回了mActivtyStarter.startActivityMayWait方法,mActivityStarter是ActivityStarter的对象,ActivityStarter是Android 7.0新加入的类,它是加载Activity的控制类,会收集所有的逻辑来决定如何将Intent和Flags转换为Activity,并将Activity和Task以及Stack相关联。我们来看它的startActivityMayWait方法
 final int startActivityMayWait(IApplicationThread caller, int callingUid,String callingPackage, Intent intent, String resolvedType,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, WaitResult outResult,Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,IActivityContainer iContainer, TaskRecord inTask, String reason) {.........code............synchronized (mService) {......code...............//启动Activityint res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,aInfo, rInfo, voiceSession, voiceInteractor,resultTo, resultWho, requestCode, callingPid,callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,options, ignoreTargetSecurity, componentSpecified, outRecord, container,inTask, reason);Binder.restoreCallingIdentity(origId);//如果配置Configration发生变化,则调用AMS的updateConfigurationLocked进行处理if (stack.mConfigWillChange) {// If the caller also wants to switch to a new configuration,// do so now.  This allows a clean switch, as we are waiting// for the current activity to pause (so we will not destroy// it), and have not yet started the next activity.//如果调用方也希望切换到新配置//现在就这样做。这允许一个干净的开关,因为我们正在等待//为当前活动暂停(因此我们不会破坏)//它还没有启动下一个活动。mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,"updateConfiguration()");stack.mConfigWillChange = false;if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,"Updating to new configuration after starting activity.");mService.updateConfigurationLocked(globalConfig, null, false);}..........code..........mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, outRecord[0]);return res;}}
startActivityMayWait这个方法的源码比较多,我们省略掉一些非重要的源码,这里重点我们看调用的 startActivityLocked方法。
int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,String callingPackage, int realCallingPid, int realCallingUid, int startFlags,ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,TaskRecord inTask, String reason) {//判断启动的理由不为空if (TextUtils.isEmpty(reason)) {throw new IllegalArgumentException("Need to specify a reason.");}mLastStartReason = reason;mLastStartActivityTimeMs = System.currentTimeMillis();mLastStartActivityRecord[0] = null;mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,container, inTask);if (outActivity != null) {// mLastStartActivityRecord[0] is set in the call to startActivity above.outActivity[0] = mLastStartActivityRecord[0];}return mLastStartActivityResult;
}
我们看到这个方法,首先判断Activity启动的理由是否为空,如果为空抛出异常,紧接着调用了它的内部方法 startActivity ,那么我们下面来继续看 startActivity 方法的源码。
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,String callingPackage, int realCallingPid, int realCallingUid, int startFlags,ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,TaskRecord inTask) {int err = ActivityManager.START_SUCCESS;// Pull the optional Ephemeral Installer-only bundle out of the options early.final Bundle verificationBundle= options != null ? options.popAppVerificationBundle() : null;ProcessRecord callerApp = null;if (caller != null) {//获取launcher进程callerApp = mService.getRecordForAppLocked(caller);if (callerApp != null) {//获取launcher进程的pid 和Uid并赋值callingPid = callerApp.pid;callingUid = callerApp.info.uid;} else {Slog.w(TAG, "Unable to find app for caller " + caller+ " (pid=" + callingPid + ") when starting: "+ intent.toString());err = ActivityManager.START_PERMISSION_DENIED;}}..............code.................//创建将要启动的Activity的描述类ActivityRecordActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,mSupervisor, container, options, sourceRecord);if (outActivity != null) {outActivity[0] = r;}..........code...............  doPendingActivityLaunchesLocked(false);return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,options, inTask, outActivity);
}
这个方法中的逻辑还是比较多的,这里还是列出我们重点关心的代码,我们看到首先在这个方法中会根据IApplicationThread类型的一个对象来获取launcher进程。随后我们又看到根据获取的进程callerApp创建一个 ActivityRecord 对象,这个类是类似与 ProcessRecord ,就是用来描述Activity,记录一个Activity对象的所有信息。所以这里创建的r就是记录将要启动的Activity的所有信息。紧接着将它传给一个ActivityRecord[]类型的的outActivity,而这个outActivity和之前创建的对象我们看到它是做为入参继续传入下一个start Activity方法。
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,ActivityRecord[] outActivity) {int result = START_CANCELED;try {mService.mWindowManager.deferSurfaceLayout();result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, outActivity);} finally {// If we are not able to proceed, disassociate the activity from the task. Leaving an// activity in an incomplete state can lead to issues, such as performing operations// without a window container.if (!ActivityManager.isStartResultSuccessful(result)&& mStartActivity.getTask() != null) {mStartActivity.getTask().removeActivity(mStartActivity);}mService.mWindowManager.continueSurfaceLayout();}postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId,  mSourceRecord,mTargetStack);return result;
}
紧接着这个方法又调用了 startActivityUnchecked方法
// Note: This method should only be called from {@link startActivity}.private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,ActivityRecord[] outActivity) {......code......// Should this be considered a new task?int result = START_SUCCESS;if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {//newTask = true;//创建新的TaskRecordresult = setTaskFromReuseOrCreateNewTask(taskToAffiliate, preferredLaunchStackId, topStack);} else if (mSourceRecord != null) {result = setTaskFromSourceRecord();} else if (mInTask != null) {result = setTaskFromInTask();} else {// This not being started from an existing activity, and not part of a new task...// just put it in the top task, though these days this case should never happen.setTaskToCurrentTopOrCreateNewTask();}if (result != START_SUCCESS) {return result;}......code......if (mDoResume) {final ActivityRecord topTaskActivity =mStartActivity.getTask().topRunningActivityLocked();if (!mTargetStack.isFocusable()|| (topTaskActivity != null && topTaskActivity.mTaskOverlay&& mStartActivity != topTaskActivity)) {mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);mWindowManager.executeAppTransition();} else {if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {mTargetStack.moveToFront("startActivityUnchecked");}mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);}} else {mTargetStack.addRecentActivityLocked(mStartActivity);}mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,preferredLaunchDisplayId, mTargetStack.mStackId);return START_SUCCESS;}
从第一行注释理解,这个方法主要处理栈管理相关的一些逻辑,启动根Activity时会将Intent的Flag设置为FLAG_ACTIVITY_NEW_TASK,所以会执行if条件里面的,在第12行我们看到会通过setTaskFromReuseOrCreateNewTask方法创建一个TaskRecord对象,TaskRecord类似于ActivityRecordd,这个类的作用是描述一个Activity任务栈,也就是说 setTaskFromReuseOrCreateNewTask方法会创建一个新的Activity任务栈。主要代码是我们看到在41行,调用的ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
   boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {if (targetStack != null && isFocusedStack(targetStack)) {return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);}final ActivityRecord r = mFocusedStack.topRunningActivityLocked();if (r == null || r.state != RESUMED) {mFocusedStack.resumeTopActivityUncheckedLocked(null, null);} else if (r.state == RESUMED) {// Kick off any lingering app transitions form the MoveTaskToFront operation.mFocusedStack.executeAppTransition(targetOptions);}return false;}
这个方法我们主要看第6行及后面的判断语句,第6行这个方法是获取启动Activity所在栈的栈顶处于非停止状态的ActivityRecord。紧接着后面判断获取的这个ActivityRecord对象为空 或者它的状态不是RESUME,就会执行if里面的语句,调用ActivityStack的 resumeTopActivityUncheckedLocked方法,对于将要启动的Activity肯定满足条件,所以下面我们来看ActivityStack的 resumeTopActivityUncheckedLocked方法,
  boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {if (mStackSupervisor.inResumeTopActivity) {// Don't even start recursing.return false;}boolean result = false;try {// Protect against recursion.mStackSupervisor.inResumeTopActivity = true;result = resumeTopActivityInnerLocked(prev, options);} finally {mStackSupervisor.inResumeTopActivity = false;}// When resuming the top activity, it may be necessary to pause the top activity (for// example, returning to the lock screen. We suppress the normal pause logic in// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.// We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure// any necessary pause logic occurs.mStackSupervisor.checkReadyForSleepLocked();return result;}
这里又调用了resumeTopActivityInnerLocked方法:
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {......code......mStackSupervisor.startSpecificActivityLocked(next, true, true);}if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return true;
}
这个方法中只需要关注调用的ActivityStackSupervisor 的startSpecificActivityLocked方法,代码如下所示:
  void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {// Is this activity's application already running?获取将要启动Activity所在应用程序的进程ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid, true);r.getStack().setLaunchTime(r);if (app != null && app.thread != null) {try {if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0|| !"android".equals(r.info.packageName)) {// Don't add this if it is a platform component that is marked// to run in multiple processes, because this is actually// part of the framework so doesn't make sense to track as a// separate apk in the process.app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,mService.mProcessStats);}realStartActivityLocked(r, app, andResume, checkConfig);return;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);}// If a dead object exception was thrown -- fall through to// restart the application.}mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);}
这个方法首先获取将要启动Activity所在应用程序的进程,之后判断该进程不为空的话,且其对象thread不为空,就会调用15行的 realStartActivityLocked方法,并且将该进程作为入参传入方法:
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,boolean andResume, boolean checkConfig) throws RemoteException {...app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);...      return true;}
上面提到app.thread指的是IApplicationThread,它的是现实ActivityThread的内部类,ApplicationThread,其中ApplicationThread继承了IApplicationThread.Stub。所以这里调用了ApplicationThread的 scheduleLuaunchActivity。说到这里就是AMS与ApplicationThread之间通过Binder通信。

总结

关于Activity的启动流程,先看到ApplicationThread这里,后面的流程后续补上,对于前面的流程相信大家看得也是云里雾里的,我们通过下面的流程图来简单总结一下:


这篇关于Android8.0源码解析——Activity的启动过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118185

相关文章

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码