浅析ActivityThread#main()方法和生命周期事务处理(代码基于Android-12)

article/2025/11/5 5:57:01

浅析ActivityThread#main()方法和生命周期事务处理(代码基于Android-12

问题:

ActivityApplicationonCreate()在哪被调用的?

ContentProvider为什么比Application先创建?

Activity#attach()在哪里被调用的?

Activity事务处理器H处理了哪些消息?
为什么onCreate()onResume()获取不到View的宽高嘞?

文章目录哟

  • 浅析`ActivityThread#main()`方法和生命周期事务处理(代码基于`Android-12`)
    • 问题:
  • 一、解析应用程序入口函数`Activity#main()`
    • 1.1 `ClientLifecycleManager#sheduleTransaction()`
    • 1.2 `main()`,你搞了什么?
      • 1.2.1 `ActivityThread#main()`
      • 1.2.2 `ActivityThread#attach()`
      • 1.2.3 `ActivityManagerService#attachApplicationLocked()`
      • 1.2.4 `ApplicationThread#bindApplication()`
      • 1.2.5 `H.handleMessage()`:`H.BIND_APPLICATION`
        • 1.2.5.1 `LoadedApk#makeApplicationInner()`
        • `Instrumentation#newApplication()`
        • 1.2.5.2 `ActivityThread#installContentProviders()`:安装`ContentProvider`如果需要的话
        • 1.2.5.3 `Instrumentation.callApplicationOnCreate()`:调用`Application.onCreate()`
    • 二、`H`事务处理
      • 1.1 `ApplicationThread#sheduleTransaction()`
      • 1.2 `ClientTransactionHandler#sheduleTransaction()`:定义了`Activity`相关操作的类
      • 1.3 `H.handleMessage()`:`H.EXECUTE_TRANSACTION`
        • 1.3.1 `TransactionExecutor.execute(ClientTransaction transaction)`
    • 这里执行`executeLifecycleState()`时会修正生命周期,先调用`onStart()`!!!具体请看 链接: [Activity的onStart()调用时机](https://blog.csdn.net/C_biubiubiu/article/details/127181469?spm=1001.2014.3001.5502)
          • 1.3.1.1 `TransactionExecutor.executeCallbacks()`:分发给具体的`ClitentTransactionItem`处理
            • 1.`ActivityThread.handleLauncherActivity()`
            • 2.`ActivityThread.performLaunchActivity()`:终于看到`Activity.onCreate()`
          • 1.3.1.2 `TransactionExecutor.executrLifecycleState()`:分发给具体的`ActivityLifecycleItem`处理
            • 1. `ActivityThread.handleResumeActivity()`
            • 2.`ActivityThread.performResumeActivity()`
            • 3. `Activity.performResume()`

一、解析应用程序入口函数Activity#main()

在文章当我点击桌面App的图标时发生了什么-浅析Activity启动流程(代码基于Android-12)中我们提到了Activity#main()何时被调用的,以及在走完main()之后又发送了LauncherActivityItem事务和ResumeActivityItem生命周期请求,接着调用远程IApplicationThread.aidl接口实现类ApplicationThread#scheduleTransaction()方法处理刚刚俩个事务请求。

1.1 ClientLifecycleManager#sheduleTransaction()

    /*** Schedule a transaction, which may consist of multiple callbacks and a lifecycle request.* @param transaction A sequence of client transaction items.* @throws RemoteException** @see ClientTransaction*/void scheduleTransaction(ClientTransaction transaction) throws RemoteException {// 设置 mClient, mClient是通过WindowProcessController获取到的IApplicationThread.aidl实现类-ApplicationThread(ActivityThread的内部类)final IApplicationThread client = transaction.getClient();// 也就是调用ApplicationThread#schedule(),阅读到这里,最好是看下ActivityThread.main()方法干了什么transaction.schedule();if (!(client instanceof Binder)) {// If client is not an instance of Binder - it's a remote call and at this point it is// safe to recycle the object. All objects used for local calls will be recycled after// the transaction is executed on client in ActivityThread.transaction.recycle();}}

那么ApplicationThread到底是什么?shedule了什么捏?

这就必须从ActivityThread#main()方法说起了!

1.2 main(),你搞了什么?

1.2.1 ActivityThread#main()

准备Loopper;

ApplicationThread对象存入AMS中以便完成各种通讯

Loopper开始轮询处理消息 - [提出问题:为什么loop()死循环不会阻塞主线程嘞?]

public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");// Install selective syscall interceptionAndroidOs.install();// CloseGuard defaults to true and can be quite spammy.  We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);// Call per-process mainline module initialization.initializeMainlineModules();Process.setArgV0("<pre-initialized>");// 1.创建主线程(也叫UI线程)LoopperLooper.prepareMainLooper();// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.// It will be in the format "seq=114"long startSeq = 0;if (args != null) {for (int i = args.length - 1; i >= 0; --i) {if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {startSeq = Long.parseLong(args[i].substring(PROC_START_SEQ_IDENT.length()));}}}// 2.创建ActivityThread对象并执行attach()方法将ApplicationThread实例传入AMSActivityThread thread = new ActivityThread();thread.attach(false, startSeq);// 3.创建事务处理Handler类-H.java实例if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);// 主线程Loopper开始轮询让H处理各种MessageLooper.loop();// 如果轮询意外终止,抛出异常throw new RuntimeException("Main thread loop unexpectedly exited");}

1.2.2 ActivityThread#attach()

ActivityThread对象创建之后,立马执行其attach()方法

// system参数为false,非系统应用
@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {sCurrentActivityThread = this;mConfigurationController = new ConfigurationController(this);mSystemThread = system;if (!system) {android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());RuntimeInit.setApplicationObject(mAppThread.asBinder());// 获取AMS,AMS是IActivityManager.aidl实现类final IActivityManager mgr = ActivityManager.getService();try {// 将mAppThread(ApplicationThread对象)存入AMS中// mAppThread是成员变量,是在声明的时候new出来的mgr.attachApplication(mAppThread, startSeq);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}// Watch for getting close to heap limit.BinderInternal.addGcWatcher(new Runnable() {@Override public void run() {if (!mSomeActivitiesChanged) {return;}Runtime runtime = Runtime.getRuntime();long dalvikMax = runtime.maxMemory();long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();if (dalvikUsed > ((3*dalvikMax)/4)) {if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)+ " total=" + (runtime.totalMemory()/1024)+ " used=" + (dalvikUsed/1024));mSomeActivitiesChanged = false;try {ActivityTaskManager.getService().releaseSomeActivities(mAppThread);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}});} else {// Don't set application object here -- if the system crashes,// we can't display an alert, we just want to die die die.android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());try {mInstrumentation = new Instrumentation();mInstrumentation.basicInit(this);ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);mInitialApplication.onCreate();} catch (Exception e) {throw new RuntimeException("Unable to instantiate Application():" + e.toString(), e);}}// 设置Configuration变化监听ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {synchronized (mResourcesManager) {// We need to apply this change to the resources immediately, because upon returning// the view hierarchy will be informed about it.if (mResourcesManager.applyConfigurationToResources(globalConfig,null /* compat */)) {// mInitialApplication是Application对象,在AMS收到ApplicationThread对象之后通知其处理BIND_APPLICATION消息后赋值的mConfigurationController.updateLocaleListFromAppContext(mInitialApplication.getApplicationContext());// This actually changed the resources! Tell everyone about it.final Configuration updatedConfig =mConfigurationController.updatePendingConfiguration(globalConfig);if (updatedConfig != null) {// 如果发生配置变化,发送CONFIGURATION_CHANGED消息,然后等待轮询处理sendMessage(H.CONFIGURATION_CHANGED, globalConfig);mPendingConfiguration = updatedConfig;}}}};ViewRootImpl.addConfigCallback(configChangedCallback);
}

1.2.3 ActivityManagerService#attachApplicationLocked()

OK,在添加Configuration变化回调的时候用到了成员变量mInitialApplication,这个变量不能为空,所以必然是在AMS.attachApplication()过程中被赋值的,所以这样反推,必须去看下这个方法的实现!

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {if (thread == null) {throw new SecurityException("Invalid application interface");}synchronized (this) {// 获取process-id,user-id,origId在ATMS中有用到int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();// 继续调用实现方法attachApplicationLocked()attachApplicationLocked(thread, callingPid, callingUid, startSeq);Binder.restoreCallingIdentity(origId);}
}

话不多说,继续跟进AMS#attachApplicationLocked()方法

@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,int pid, int callingUid, long startSeq) {// .....// 调用IApplicationThread.aidl实现类ApplicationThread的bindApplication()方法thread.bindApplication(processName, appInfo,app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,providerList, null, profilerInfo, null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.getCompat(), getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions,app.getDisabledCompatChanges(), serializedSystemFontMap,app.getStartElapsedTime(), app.getStartUptime());
}

这里看到,在配置获取了超多参数的值之后,远程调用传进来的ApplicationThread对象的bindApplication()方法,似乎很快就能看到Application对象(mInitialApplication)的赋值地方了!

1.2.4 ApplicationThread#bindApplication()

文件链接:ApplicationThread.aidl

ApplicationThreadIApplicationThread.aidl实现,这个文件中包含了有关四大组件绑定启动,销毁等各种回调方法,

具体的代码看上面的链接。

@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,ProviderInfoList providerList, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableBinderTracking, boolean trackAllocation,boolean isRestrictedBackupMode, boolean persistent, Configuration config,CompatibilityInfo compatInfo, Map services, Bundle coreSettings,String buildSerial, AutofillOptions autofillOptions,ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,SharedMemory serializedSystemFontMap,long startRequestedElapsedTime, long startRequestedUptime) {if (services != null) {if (false) {// Test code to make sure the app could see the passed-in services.for (Object oname : services.keySet()) {if (services.get(oname) == null) {continue; // AM just passed in a null service.}String name = (String) oname;// See b/79378449 about the following exemption.switch (name) {case "package":case Context.WINDOW_SERVICE:continue;}if (ServiceManager.getService(name) == null) {Log.wtf(TAG, "Service " + name + " should be accessible by this app");}}}// Setup the service cache in the ServiceManagerServiceManager.initServiceCache(services);}setCoreSettings(coreSettings);// 新建AppBindData, 用于创建ApplicationAppBindData data = new AppBindData();data.processName = processName;data.appInfo = appInfo;data.sdkSandboxClientAppVolumeUuid = sdkSandboxClientAppVolumeUuid;data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;data.providers = providerList.getList();data.instrumentationName = instrumentationName;data.instrumentationArgs = instrumentationArgs;data.instrumentationWatcher = instrumentationWatcher;data.instrumentationUiAutomationConnection = instrumentationUiConnection;data.debugMode = debugMode;data.enableBinderTracking = enableBinderTracking;data.trackAllocation = trackAllocation;data.restrictedBackupMode = isRestrictedBackupMode;data.persistent = persistent;data.config = config;data.compatInfo = compatInfo;data.initProfilerInfo = profilerInfo;data.buildSerial = buildSerial;data.autofillOptions = autofillOptions;data.contentCaptureOptions = contentCaptureOptions;data.disabledCompatChanges = disabledCompatChanges;data.mSerializedSystemFontMap = serializedSystemFontMap;data.startRequestedElapsedTime = startRequestedElapsedTime;data.startRequestedUptime = startRequestedUptime;// 配置好data后,发送BIND_APPLICATION消息,注意此时主线程Loopper并没有对MessageQueue进行轮询哦sendMessage(H.BIND_APPLICATION, data);
}

这个方法执行到最后是向MQ中发送一条BIND_APPLICATION消息,大家别忘记了哟,在启动Activity那里,创建进程走完main()方法之后,向ApplicationThread发送了LauncherActivityItem事务和ResumeActivityItem生命周期请求,其中这俩个item最后是调用ApplicationThread#sheduleTransaction()方法处理的。

所以,捋一下,走完ActivityThread#attach()之后,消息队列中有一条BIND_APPLICATION消息,然后对消息队列进行轮询处理之前存入的消息,所以轮询后先处理了BIND_APPLICATION消息,然后再ActivityTaskASupervisor#realStartActivityLocked()那里调用ApplicationThread#sheduleTransaction()处理那俩个ClientTransactionItem,话不多说,先看一下``loop()后处理的第一条消息BIND_APPLICATION,然后看ApplicationThread#sheduleTransaction()吧!消息都是在ActivityThread.H`里处理的

1.2.5 H.handleMessage()H.BIND_APPLICATION

H类中定义了非常多的消息类型,大概有70多种,分别处理了四大组件相关的消息等,很复杂,不过都能一一找到,最后都是汇总到这里根据具体的消息处理具体的操作。

public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {// ....case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");// 在AMS.attachApplicationLocked()中创建的AppBindDataAppBindData data = (AppBindData)msg.obj;// 调用ActivityThread.handleBindApplition(),完成Application创建handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;}
}

最终还是调用ActivityThread#handleBindApplication()

还有其他类似handleXXXX方法,调用链应该差不多。

跟进进去吧!

@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {// VM相关配置// 设置时区,时间格式// 是否是Debugger模式,是否显示那个"Wait for Debugger"对话框// 硬件渲染设置// Instrumentation info affects the class loader, so load it before// setting up the app context.// Instrumentation类对象,这个类里面是具体的四大组件相关的操作的逻辑实现类,具体的逻辑代码由这个类承担final InstrumentationInfo ii;if (data.instrumentationName != null) {ii = prepareInstrumentation(data);} else {ii = null;}// 创建 ContextImplfinal ContextImpl appContext = ContextImpl.createAppContext(this, data.info);// 更新ConfigurationController里的contextmConfigurationController.updateLocaleListFromAppContext(appContext);// HTTP相关代理类配置// For backward compatibility, TrafficStats needs static access to the application context.// But for isolated apps which cannot access network related services, service discovery// is restricted. Hence, calling this would result in NPE.if (!Process.isIsolated()) {TrafficStats.init(appContext);}// Continue loading instrumentation.// 初始化 Instrumentationif (ii != null) {initInstrumentation(ii, data, appContext);} else {mInstrumentation = new Instrumentation();mInstrumentation.basicInit(this);}// 芜湖!终于看到Application咯Application app;final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();try {// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.// 创建App, data.info是LoadedApk对象app = data.info.makeApplicationInner(data.restrictedBackupMode, null);// Propagate autofill compat stateapp.setAutofillOptions(data.autofillOptions);// Propagate Content Capture optionsapp.setContentCaptureOptions(data.contentCaptureOptions);// 向H发送H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACKsendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);// 看到没,这个mInitialApplication被赋值了,然后再ActivityThread.attach()方法最后面用到了mInitialApplication = app;final boolean updateHttpProxy;synchronized (this) {updateHttpProxy = mUpdateHttpProxyOnBind;}if (updateHttpProxy) {ActivityThread.updateHttpProxy(app);}if (!data.restrictedBackupMode) {// 安装ContentProviderif (!ArrayUtils.isEmpty(data.providers)) {installContentProviders(app, data.providers);}}// Do this after providers, since instrumentation tests generally start their// test thread at this point, and we don't want that racing.try {mInstrumentation.onCreate(data.instrumentationArgs);}catch (Exception e) {throw new RuntimeException("Exception thrown in onCreate() of "+ data.instrumentationName + ": " + e.toString(), e);}try {// OK,终于看到了,调用Application.onCreate()mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}} finally {// If the app targets < O-MR1, or doesn't change the thread policy// during startup, clobber the policy to maintain behavior of b/36951662if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {StrictMode.setThreadPolicy(savedPolicy);}}// 加载字体什么的}

看完代码后心情舒畅,在这段中,看到了Application是由谁创建的,它的onCreate()是谁调用的,以及ContentProvider为什么是在Application之前创建的,接下来按这个逻辑分三部分展开:

1.2.5.1 LoadedApk#makeApplicationInner()

文件指定方法位置:LoadedApk#makeApplicationInner()

具体的代码可以看链接,这里放出创建逻辑

// 缓存中没有app的话就创建一个新的,调用Instrumentation.newApplication()
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
  • Instrumentation#newApplication()

    public Application newApplication(ClassLoader cl, String className, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {// 调用ClassLoader创建appApplication app = getFactory(context.getPackageName()).instantiateApplication(cl, className);// 完事之后调用Application.attach(),平平无奇app.attach(context);return app;
    }public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,@NonNull String className)throws InstantiationException, IllegalAccessException, ClassNotFoundException {return (Application) cl.loadClass(className).newInstance();
    }@UnsupportedAppUsage/* package */ final void attach(Context context) {attachBaseContext(context);mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;}
    

1.2.5.2 ActivityThread#installContentProviders():安装ContentProvider如果需要的话

@UnsupportedAppUsage
private void installContentProviders(Context context, List<ProviderInfo> providers) {// 最终走到ContentProvider.onCreate()
}

1.2.5.3 Instrumentation.callApplicationOnCreate():调用Application.onCreate()

先来感受一下callXXOnXXX()系列方法,会有一个整体上的感知。

在这里插入图片描述

public void callApplicationOnCreate(Application app) {// 调用Application.onCreate()app.onCreate();
}

好的,到这里,已经处理完H.BIND_APPLICATION消息,其中还发送了一个消息H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK,暂时不管了,就当它也处理了。好的现在是ActivityThread#main()方法走完了,之后还有俩个要处理的消息喔,别忘记了哟:

  1. LauncherActivityItem
  2. ResumeActivityItem

这俩个类均是继承自ClientTransactionItem

好的,后续是远程调用ApplicationThread.sheduleTransaction()处理事务了。

二、H事务处理

1.1 ApplicationThread#sheduleTransaction()

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {ActivityThread.this.scheduleTransaction(transaction);
}

调用ActivityThread#scheduleTransaction()方法,注意哦,这个方法并不在ActivityThread类中,而是在它的父类 ClientTransactionHandler中,继续跟进!

public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {// ....
}

1.2 ClientTransactionHandler#sheduleTransaction():定义了Activity相关操作的类

文件链接:ClientTransactionHandler

/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {// 预处理,设置client端相关变量-即ActivityThread对象中一些变量transaction.preExecute(this);// 发送一条H.EXECUTE_TRANSACTION消息让H处理,obj为当前的事务sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

1.3 H.handleMessage()H.EXECUTE_TRANSACTION

public void handleMessage(Message msg) {case EXECUTE_TRANSACTION:final ClientTransaction transaction = (ClientTransaction) msg.obj;// 调用ActivityThread成员变量mTransactionExecutor处理transactionmTransactionExecutor.execute(transaction);if (isSystem()) {// Client transactions inside system process are recycled on the client side// instead of ClientLifecycleManager to avoid being cleared before this// message is handled.transaction.recycle();}// TODO(lifecycler): Recycle locally scheduled transactions.break;
}

具体的处理逻辑封装在了TransactionExecutor类中的#execute()方法中;

这个类文件链接:TransactionExecutor

1.3.1 TransactionExecutor.execute(ClientTransaction transaction)

public void execute(ClientTransaction transaction) {// ....// 1.执行ClientTransactionItem callbacksexecuteCallbacks(transaction);// 2.执行ActivityLifecycleItems requestsexecuteLifecycleState(transaction);mPendingActions.clear();}

这里执行executeLifecycleState()时会修正生命周期,先调用onStart()!!!具体请看 链接: Activity的onStart()调用时机

代码不多,可以看到清晰地看到分别处理ClientTransactionItemActivityLifecycleItem,怕你们忘记了,砸门在这里贴一段生成这个俩个东东的地方哈,如下。小过一遍后,继续往下看是怎么处理这俩个东西的吧。

ActivityTaskSupervisor#realStartActivityLocked()boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,boolean andResume, boolean checkConfig) throws RemoteException {// ....final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);final boolean isTransitionForward = r.isTransitionForward();final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();// 1.创建启动activity事务到待处理列表中[LaunchActivityItem]clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),System.identityHashCode(r), r.info,// TODO: Have this take the merged configuration instead of separate global// and override configs.mergedConfiguration.getGlobalConfiguration(),mergedConfiguration.getOverrideConfiguration(), r.compat,r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),results, newIntents, r.takeOptions(), isTransitionForward,proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));// 2。创建ActivityLifecycleItem对象final ActivityLifecycleItem lifecycleItem;if (andResume) {// 设置resume-itemlifecycleItem = ResumeActivityItem.obtain(isTransitionForward);} else {// 设置pause-itemlifecycleItem = PauseActivityItem.obtain();}// 设置lifecycle请求,也就是onCreate之后是onResumeclientTransaction.setLifecycleStateRequest(lifecycleItem);// Schedule transaction.// 开始处理事务!~!!!!!!// mService是ActivityTaskManagerService,获取到的lm是ClientLifecycleManager对象mService.getLifecycleManager().scheduleTransaction(clientTransaction);// ....
}
1.3.1.1 TransactionExecutor.executeCallbacks():分发给具体的ClitentTransactionItem处理
/** Cycle through all states requested by callbacks and execute them at proper times. */@VisibleForTestingpublic void executeCallbacks(ClientTransaction transaction) {// 拿到所有的TransactionItemfinal List<ClientTransactionItem> callbacks = transaction.getCallbacks();// 空判断if (callbacks == null || callbacks.isEmpty()) {// No callbacks to execute, return early.return;}final IBinder token = transaction.getActivityToken();ActivityClientRecord r = mTransactionHandler.getActivityClient(token);// In case when post-execution state of the last callback matches the final state requested// for the activity in this transaction, we won't do the last transition here and do it when// moving to final state instead (because it may contain additional parameters from server).// 拿到所有的ActivityLifecycleItem,这里是为了获取生命周期顺序状态状态final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState(): UNDEFINED;// Index of the last callback that requests some post-execution state.final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);final int size = callbacks.size();// 分发处理各个ClientTransactionItem-----LaunchActivityItemfor (int i = 0; i < size; ++i) {final ClientTransactionItem item = callbacks.get(i);final int postExecutionState = item.getPostExecutionState();final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,item.getPostExecutionState());if (closestPreExecutionState != UNDEFINED) {cycleToPath(r, closestPreExecutionState, transaction);}// 这里具体执行了LaunchActivityItem.execute()方法item.execute(mTransactionHandler, token, mPendingActions);item.postExecute(mTransactionHandler, token, mPendingActions);if (r == null) {// Launch activity request will create an activity record.r = mTransactionHandler.getActivityClient(token);}if (postExecutionState != UNDEFINED && r != null) {// Skip the very last transition and perform it by explicit state request instead.final boolean shouldExcludeLastTransition =i == lastCallbackRequestingState && finalState == postExecutionState;cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);}}}

逻辑还是很清晰的,因为这是专门处理ClientTransactionItem的,所以获取了所有的,然后遍历分发给具体的实现对象处理,也就是分别调用ClientTransactionItem.execute()方法,由于我们添加进去的是一个LaunchActiivtyItem,所以执行LauncherActivityItem.execute()方法!OKK,GO!

@Overridepublic void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {// 创建ACRActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,mTaskFragmentToken);// 当前client端是ActivityThread对象(上面说过,它是ClientTransactionHandler子类)client.handleLaunchActivity(r, pendingActions, null /* customIntent */);}

兜兜转转,最终还是到了ActivityThread

处理LaunchActivityItem最终是转为了一个ActivityClientRecord对象,继而交给具体的ActivityThread.handleLauncherActivity()处理!

当然,ActivityThread还有很多handleXXXX系列方法(方法之多,一屏装不下),原理差不多。

在这里插入图片描述

找到handleLauncherActivity()

1.ActivityThread.handleLauncherActivity()
@Overridepublic Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {// .....// 初始化WindowManagerGlobal,与WM,WMS强相关WindowManagerGlobal.initialize();// Hint the GraphicsEnvironment that an activity is launching on the process.GraphicsEnvironment.hintActivityLaunch();// 哇哦!创建了Activity对象!调用自身的performLaunchActivity()final Activity a = performLaunchActivity(r, customIntent);// ..return a;}

看到WindowManagerGlobal被初始化(后续研究WMS,WM,VIEW再细说),还看到Activity被创建,与上面一样,同系列performXXX方法也有很多。

在这里插入图片描述

找到performLaunchActivity()返回俺们的Activity

2.ActivityThread.performLaunchActivity():终于看到Activity.onCreate()
/**  Core implementation of activity launch. */private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {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);}// 获取appContextContextImpl appContext = createBaseContextForActivity(r);// 声明Activity空对象Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();// 调用Instrumentation去new一个Activity,和new Application是一样的// 都是通过ClassLoader搞出来的// TIPS:由于我们默认创建的Activity是继承自AppComatActivity的(空构造),所以在创建实例的时候会调用其空构造器中的代码,主要是用来初始化AppCompatDelege类,通过ContextAware(实现类为ComponetActivity).addOnContextAvailableListener(),这个回调会在Activity.onCreate()中被调用activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),appContext.getAttributionSource());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 (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config =new Configuration(mConfigurationController.getCompatConfiguration());if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}// 配置window,复用之前的Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}// Activity resources must be initialized with the same loaders as the// application context.appContext.getResources().addLoaders(app.getResources().getLoaders().toArray(new ResourcesLoader[0]));appContext.setOuterContext(activity);// !!!! activity对象创建好之后,调用其attach()方法,完成内部变量初始化// PhoneWindow,title.....activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken, r.shareableActivityToken);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();// 如果设置了自定义的主题,设置上去if (theme != 0) {activity.setTheme(theme);}if (r.mActivityOptions != null) {activity.mPendingOptions = r.mActivityOptions;r.mActivityOptions = null;}activity.mLaunchedFromBubble = r.mLaunchedFromBubble;activity.mCalled = false;// 根据是否是持久化的来调用Acitivty.onCreate(),主要是参数个数不同,有些同学会写成三个参数的onCreate()从而导致为啥我的onCreate()不执行的问题if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {// 与上面Application.onCreate()调用是一样的// 调用了核心逻辑实现类Instrumentation.callActivityOnCreate()mInstrumentation.callActivityOnCreate(activity, r.state);}// 检查Activity子类是否调用对应的super.method,也就是为什么我们重写onCreate(),如果吧super.onCreate()去掉AS会提示缺少CallSuper异常if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;mLastReportedWindowingMode.put(activity.getActivityToken(),config.windowConfiguration.getWindowingMode());}// 设置Activity声明周期为onCreater.setState(ON_CREATE);// updatePendingActivityConfiguration() reads from mActivities to update// ActivityClientRecord which runs in a different thread. Protect modifications to// mActivities to avoid race.synchronized (mResourcesManager) {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;}

OKK,在这个方法中我们看到Activity对象的创建也是由Instrumetation负责,先是调用Activity.attach(),然后调用了Activity.onCreate()方法!

我们看完了LaunchActivityItem的处理,再来看ResumeActivityItem的处理,不知道你们忘记了没有,其对应的方法是:

public void execute(ClientTransaction transaction) {// ....// 1.执行ClientTransactionItem callbacksexecuteCallbacks(transaction);// 2.执行ActivityLifecycleItems requestsexecuteLifecycleState(transaction);mPendingActions.clear();}

让我们回到这一小节的TransactionExecutor.execute()方法中,在1.3.1.1中完成了executeCallbacks(transaction)方法执行,然后就是轮到ResumeActivityItem(extend ActivityLifecycleItem)的处理!

1.3.1.2 TransactionExecutor.executrLifecycleState():分发给具体的ActivityLifecycleItem处理
/** Transition to the final state if requested by the transaction. */private void executeLifecycleState(ClientTransaction transaction) {final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();// onResume之后,activity正常走,不做什么隐藏,主题变化等,就不会有生命周期改变if (lifecycleItem == null) {// No lifecycle request, return early.return;}final IBinder token = transaction.getActivityToken();final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);if (r == null) {// Ignore requests for non-existent client records for now.return;}// 确保生命周期顺序正确// Cycle to the state right before the final requested state.cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);// Execute the final transition with proper parameters.// 同处理ClientTransactionItem一样,调用其execute()方法lifecycleItem.execute(mTransactionHandler, token, mPendingActions);lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);}

这里看到和上面的差不多,分发给ReusmeActivityItem自己处理,同理其他的生命周期item也是一样的。

还是调用ActivityThread.handleXXX系列方法。

此处调用handleResumeActivity()

 @Overridepublic void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {//Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,"RESUME_ACTIVITY");//Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}
1. ActivityThread.handleResumeActivity()
@Overridepublic void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {// ....// TODO Push resumeArgs into the activity for consideration// skip below steps for double-resume and r.mFinish = true case.// 执行performResumeActivity()if (!performResumeActivity(r, finalStateRequest, reason)) {return;}if (mActivitiesToBeDestroyed.containsKey(r.token)) {// Although the activity is resumed, it is going to be destroyed. So the following// UI operations are unnecessary and also prevents exception because its token may// be gone that window manager cannot recognize it. All necessary cleanup actions// performed below will be done while handling destruction.return;}final Activity a = r.activity;final int forwardBit = isForward? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;// If the window hasn't yet been added to the window manager,// and this guy didn't finish itself or start another activity,// then go ahead and add the window.boolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {willBeVisible = ActivityClient.getInstance().willActivityBeVisible(a.getActivityToken());}// =================== 准备关联WM WMS ViewRootImpl DecorView,if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();a.mDecor = decor;// 设置该window为应用程序顶级窗口l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;if (r.mPreserveWindow) {a.mWindowAdded = true;r.mPreserveWindow = false;// Normally the ViewRoot sets up callbacks with the Activity// in addView->ViewRootImpl#setView. If we are instead reusing// the decor view we have to notify the view root that the// callbacks may have changed.ViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;// 将DecorView和ViewRootImpl等关联起来,准备三大流程wm.addView(decor, l);} else {// The activity will get a callback for this {@link LayoutParams} change// earlier. However, at that time the decor will not be set (this is set// in this method), so no action will be taken. This call ensures the// callback occurs with the decor set.a.onWindowAttributesChanged(l);}}// If the window has already been added, but during resume// we started another activity, then don't yet make the// window visible.} else if (!willBeVisible) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");r.hideForNow = true;}// Get rid of anything left hanging around.cleanUpPendingRemoveWindows(r, false /* force */);// The window is now visible if it has been added, we are not// simply finishing, and we are not starting another activity.if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();WindowManager.LayoutParams l = impl != null? impl.mWindowAttributes : r.window.getAttributes();if ((l.softInputMode& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)!= forwardBit) {l.softInputMode = (l.softInputMode& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))| forwardBit;if (r.activity.mVisibleFromClient) {ViewManager wm = a.getWindowManager();View decor = r.window.getDecorView();wm.updateViewLayout(decor, l);}}r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {r.activity.makeVisible();}}r.nextIdle = mNewActivities;mNewActivities = r;if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);Looper.myQueue().addIdleHandler(new Idler());}

可以看到还是得执行performResumeActivity(),和之前oncreate时一样,之后就是和Window-DecorView-RootView-三大流程相关了。

2.ActivityThread.performResumeActivity()
    public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,String reason) {if (r.activity.mFinished) {return false;}// 在performLaunchActivity()那里,r.setState(ON_CREATE),如果走到这里,state居然为onResume,那么就是意外情况了if (r.getLifecycleState() == ON_RESUME) {if (!finalStateRequest) {final RuntimeException e = new IllegalStateException("Trying to resume activity which is already resumed");Slog.e(TAG, e.getMessage(), e);Slog.e(TAG, r.getStateString());// TODO(lifecycler): A double resume request is possible when an activity// receives two consequent transactions with relaunch requests and "resumed"// final state requests and the second relaunch is omitted. We still try to// handle two resume requests for the final state. For cases other than this// one, we don't expect it to happen.}return false;}if (finalStateRequest) {r.hideForNow = false;r.activity.mStartedActivity = false;}try {r.activity.onStateNotSaved();r.activity.mFragments.noteStateNotSaved();checkAndBlockForNetworkAccess();if (r.pendingIntents != null) {deliverNewIntents(r, r.pendingIntents);r.pendingIntents = null;}if (r.pendingResults != null) {deliverResults(r, r.pendingResults, reason);r.pendingResults = null;}// !!!  调用Activity.performResume()r.activity.performResume(r.startsNotResumed, reason);r.state = null;r.persistentState = null;// 生命周期右 ON_CREATE -> ON_RESUMEr.setState(ON_RESUME);reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to resume activity "+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);}}return true;}

可以看到,先做了不正常生命周期判断,正常流程就是执行Activity.performResume(),然后更新ActivityClientRecor中的生命周期,由ON_CREATE---->ON_RESUME

3. Activity.performResume()

Activity中也有系列方法:

在这里插入图片描述

final void performResume(boolean followedByPause, String reason) {// 调用Application分发ActivityLifecycleCallbacks注册回调dispatchActivityPreResumed();// 这里看判断是不是STTOPED,如果是执行onRestart,由于是从oncreate->onresume,并没有到onstop,所以这这个方法并不会执行完整performRestart(true /* start */, reason);mFragments.execPendingActions();mLastNonConfigurationInstances = null;// ...mCalled = false;// mResumed is set by the instrumentation// 同oncreate,还是调用Instrumentation.callActivityOnResume()mInstrumentation.callActivityOnResume(this);// .....// fragment相关mFragments.dispatchResume();mFragments.execPendingActions();onPostResume();// ...检测是否CallSuperif (!mCalled) {throw new SuperNotCalledException("Activity " + mComponent.toShortString() +" did not call through to super.onPostResume()");}dispatchActivityPostResumed();Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);}

判断是否需要restart,然后调用Instrumentation.callActiivtyOnResume()

public void callActivityOnResume(Activity activity) {activity.mResumed = true;// 调用Activity.onResumeactivity.onResume();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.onResume()被调用!

至此,ActivityThread.handleResume()方法中的performResumeActivity()执行完了,然后会继续执行和Window相关显示,开启View三大流程将Activity默认布局显示出来(如果在Activity.onCreate()还设置了setContnentView(layoutResId),还会继续显示),这也解释了为什么onCreate()onResume()获取不到View的宽高!!!!


http://chatgpt.dhexx.cn/article/Ow4xrHht.shtml

相关文章

Android中的ActivityThread和ApplicationThread

一&#xff1a;ActivityThread和ApplicationThread 1.ActivityThread&#xff1a;主线程、UI线程&#xff0c;程序的入口&#xff08;main函数&#xff09;&#xff0c;不是线程是运行在主线程中的一个对象 主要的成员变量如下&#xff1a; mActivities、mServices和mProvide…

一文读懂ActivityThread

ActivityThread是什么&#xff0c;是主线程吗&#xff1f;它是如何被创建的&#xff0c;以及它的作用又是什么呢&#xff1f;带着这些问题&#xff0c;我们一起来分析下ActivityThread。 全文分为以下几个部分&#xff0c;大家可根据需求阅读 文章目录 ActivityThread是什么Act…

Android ActivityThread(主线程或UI线程)简介

1. ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数)&#xff0c;并根据AMS的要求&#xff08;通过IApplicationThread接口&#xff0c;AMS为Client、ActivityThread.ApplicationThread为Server&#xff09;负责调度和执行activities、broa…

ActivityThread的理解和APP的启动过程

ActivityThread的理解和APP的启动过程 ActivityThreadActivityThread的初始化主线程Looper的初始化主线程Handler的初始化ApplicationThread及Activity的创建和启动 APP的启动系统的启动过程APP的启动过程APP启动过程的部分代码思考 总结 ActivityThread ActivityThread就是我…

validate中remote返回函数中+号导致submitHandler无法执行

validate中remote返回函数中号导致submitHandler无法执行 这是2017年以来我遇到的最无语的bug&#xff0c;现在暂时还没想到原因&#xff0c;但是这个错误真的很无语。 这是我的validate中rule的定义&#xff0c;其中 new Date; 采用至慕课网上validate插件视频中的例子。 rul…

jQuery(六)插件、Validate验证提交表单、submitHandler、更改错误信息显示的位置、required、Validator、内置验证方式表、validate ()的可选项汇总

jQuery&#xff08;六&#xff09;插件、Validate验证提交表单、submitHandler、更改错误信息显示的位置、required、Validator、内置验证方式表、validate ()的可选项汇总 文章目录 jQuery&#xff08;六&#xff09;插件、Validate验证提交表单、submitHandler、更改错误信息…

ajax post 不起作用,jQuery验证submitHandler在$ .ajax post表单数据中不起作用

我使用$.ajax发送数据并使用jQuery验证插件进行验证&#xff0c;如下所示&#xff1a; Send JS&#xff1a; jQuery(document).ready(function ($) { $(#myform).validate({ rules: { name: { required: true, rangelength: [4, 20], }, }, submitHandler: function (form) { $…

FileReader()用法

FileReader()用法HTML5定义了FileReader作为文件API的重要成员用于读文件&#xff0c;根据W3C的定义&#xff0c;FileReaderr接口提供了读取文件的方法和包含读取 结果的事件模型。 FileReader的方法使用比较简单&#xff0c;可以按照以下步骤创建FileReader对象并调用其他的方…

read/write/fsync与fread/fwrite/fflush的关系和区别

read/write/fsync&#xff1a; 1. linux底层操作&#xff1b; 2. 内核调用&#xff0c; 涉及到进程上下文的切换&#xff0c;即用户态到核心态的转换&#xff0c;这是个比较消耗性能的操作。 fread/fwrite/fflush&#xff1a; 1. c语言标准规定的io流操作&#xff0c;建立…

FileReader详解

我在Google Chrome Web Store上发布了一个案例hahaOCR&#xff0c;该扩展程序可以帮助用户识别出图片中的文字信息&#xff0c;并以文本形式显示&#xff0c;大家可以在chrome网上应用商店中找到我发布的应用程序&#xff0c;如图所示&#xff1a; 图1 - hahaOCR 该扩展程序支持…

f.readlines()

f.readlines() ftext open(1299_wangyifei_edit.pinyin, r, encodingutf-8)lines ftext.readlines()print("lines",lines)l ftext.readlines()print("l",l)输出结果&#xff1a; 原因&#xff1a; readlines() 方法用于读取所有行(直到结束符 EOF)并返…

FileReader的用法

FileReader是一种异步文件读取机制&#xff0c;结合input:file可以很方便的读取本地文件。 input:file input的file类型会渲染为一个按钮和一段文字。点击按钮可打开文件选择窗口&#xff0c;文字表示对文件的描述&#xff08;大部分情况下为文件名&#xff09;&#xff1b;…

【原创】通过 ioctl + FIONREAD 判定数据可读

【原创】通过 ioctl FIONREAD 判定数据可读 摩云飞 2016-05-12 09:57:51 浏览470 评论0 libevent ioctl FIONREAD 摘要&#xff1a; 在排查业务 bug 的过程中&#xff0c;看到如下两种输出信息&#xff1a; TCP 连接正常情况下&#xff0c;进行数据读取 14:00:38 epoll_ctl…

fread函数详解

文章迁移&#xff1a; fread函数详解 - 码到城攻fread函数详解&#xff0c;C函数使用注意事项&#xff0c;freadhttps://www.codecomeon.com/posts/93/ 函数原型&#xff1a; size_t fread( void *buffer, size_t size, size_t count, FILE *stream ) buf…

SQLSTATE: Insert value list does not match column list: 1136 Column count doesn‘t match value count

使用thinkphp5的insertAll的批量新增函数&#xff0c;提示SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesnt match value count at row 2 其意思就是&#xff1a;在第二行数据开始&#xff0c;插入的&#xff0c;每行数据的值的个数和…

Column-Stores vs. Row-Stores: How Different Are They Really

概述 从论文的标题可以看出这篇论文不是陈述一种新的技术、架构&#xff0c;而更偏议论文一点&#xff0c;它主要的目的在于搞清楚对于分析类的查询为什么Column-Store比Row-Store好那么多&#xff1f;好在哪里&#xff1f;一般认为原因是: 分析类查询往往只查询一个表里面很少…

Android应用开发之( TableLayout中stretchColumns、shrinkColumns的用法)

从字面上来看&#xff0c;TableLayout也比较简单&#xff0c;关键是要对相关的属性要熟悉&#xff0c;先看一个简单的例子&#xff08;后面为效果图&#xff09;&#xff1a; <?xml version"1.0" encoding"utf-8"?> <TableLayout xmlns:android…

CollenctionList

1.Collection集合 1.1集合体系结构【记忆】 集合类的特点 提供一种存储空间可变的存储模型&#xff0c;存储的数据容量可以随时发生改变 集合类的体系图 1.2Collection集合概述和基本使用【应用】 Collection集合概述 是单例集合的顶层接口&#xff0c;它表示一组对象&#xff…

输入界面,关于stretchColumns和selectAllOnFocus的属性设置

这是整个TableLayout的代码&#xff1a; <TableLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:orientation"vertical"android:layout_width"fill_parent&qu…

android:stretchcolumns=0,1,2,3,stretch_stretch是什么意思

stretch是什么意思 stretch是伸展、可伸缩的意思。具体释义如下&#xff1a; stretch英 [stretʃ] 美 [strɛtʃ] 1、动词 v.伸展;延伸;持续;包括 例&#xff1a;It is better to stretch the tight muscles first 最好先伸展一下僵硬的肌肉。 2、名词 n.伸展;弹性;一片;一…