【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
– 服装学院的IT男
本篇已收录于Activity短暂的一生系列
欢迎一起学习讨论Android应用开发或者WMS
V:WJB6995
Q:707409815
正文

生命周期系列:
-
Activity生命周期之onPause
-
onCreate,onStart,onResume-1
-
onCreate,onStart,onResume-2
-
Activity生命周期之onStop-1
-
Activity生命周期之onStop-2
-
Activity生命周期之onDestory
本篇为"onCreate,onStart,onResume"的第二篇,介绍应用端 onCreate,onStart,onResume 的处理
1. onCreate
onCreate 是一个新 Activity 启动的第一个生命周期。而且根据前面的铺垫,也知道了他是在 onStart 和 onResume 执行的。
对应的事务为 LaunchActivityItem
# LaunchActivityItem@Overridepublic void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {// traceTrace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,mTaskFragmentToken);// 应用段处理client.handleLaunchActivity(r, pendingActions, null /* customIntent */);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}@Overridepublic void postExecute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {client.countLaunchingActivities(-1);}
完整的调用链如下:
LaunchActivityItem::executeActivityThread::handleLaunchActivityActivityThread::performLaunchActivityInstrumentation::newActivity --- 创建ActivityActivity::attach --- 创建WindowWindow::initWindow::setWindowManagerInstrumentation::callActivityOnCreate Activity::performCreateActivity::onCreate --- onCreateActivityClientRecord::setState --- 设置状态为 ON_CREATE(1)
这部分的代码其实在【Activity启动流程-3】的末尾有解释,单独拎出来再看一遍。
# ActivityThreadpublic Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {......final Activity a = performLaunchActivity(r, customIntent);......}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {......Activity activity = null;try {// 重点* 1. 通过Instrumentation 反射创建Activityjava.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);......}try {......// 重点* 2. 执行 attach 流程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.activityConfigCallback,r.assistToken, r.shareableActivityToken);if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {重点* 3. OnCreate流程mInstrumentation.callActivityOnCreate(activity, r.state);}// 设置状态为 ON_CREATE(1)r.setState(ON_CREATE);} ............}# Instrumentationpublic void callActivityOnCreate(Activity activity, Bundle icicle) {prePerformCreate(activity);// onCreate流程activity.performCreate(icicle);postPerformCreate(activity);}
# Activityfinal void performCreate(Bundle icicle) {performCreate(icicle, null);}final void performCreate(Bundle icicle, PersistableBundle persistentState) {......if (persistentState != null) {onCreate(icicle, persistentState);} else {// 执行onCreateonCreate(icicle);}// wm_on_create_calledEventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(),"performCreate");......}
onCreate 的流程还是比较简单的,在 ActivityThread::performLaunchActivity 做了四件事:
-
- 反射创建 Activity 对象
-
- 执行 activity.attach,这里会创建Window
-
- 执行到 onCreate 生命周期
-
- 设置 ActivityClientRecord 中的状态为 ON_CREATE(1)
这里需要留意下会先执行 Activity::attach 来创建Window,然后才是后面的 Activity的onCreate。
创建 Window 的时候会创建 DecorView,有了这个 DecorView 我们在 onCreate 的时候才可以把对应的XML布局设置进去。
2. onStart
onStart 也有其对应的一个事务: StartActivityItem ,我一度以为启动 Activity 的时候也是通过这个事务来触发 onStart 的,但是实际情况我有点意外,它不是通过事务触发的,而是在执行 ResumeActivityItem 前,通过 TransactionExecutor::cycleToPath 触发的。
按下 recent 键再回到 Activity,这个时候onStart 是通过 StartActivityItem 触发的
当前分析 TransactionExecutor::cycleToPath 方法
# TransactionExecutor// 工具类private TransactionExecutorHelper mHelper = new TransactionExecutorHelper(); private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,ClientTransaction transaction) {// 1. 获取当前ActivityClientRecord的生命周期状态值final int start = r.getLifecycleState();// log if (DEBUG_RESOLVER) {Slog.d(TAG, tId(transaction) + "Cycle activity: "+ getShortActivityName(r.token, mTransactionHandler)+ " from: " + getStateName(start) + " to: " + getStateName(finish)+ " excludeLastState: " + excludeLastState);}// 2. 根据起始状态、结束状态以及是否排除最后一个状态,计算出生命周期状态变化的路径final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);// 3. 按照计算出的生命周期状态路径顺序执行相关操作performLifecycleSequence(r, path, transaction);}
-
- 获取到当前 Activity 的生命周期状态,目前是 ON_CREATE 也就是 1
-
- 通过工具类 计算出生命周期变化的路径,这个路径是啥呢, 比如说当前是 ON_CREATE(1),需要到 ON_RESUME(3), 那路径就是 [2]
-
- 根据第二步计算的路径开始执行各个生命周期
2.1 getLifecyclePath 计算生命周期切换路径
TransactionExecutor::getLifecyclePath 方法完整代码和解释都在下面了,但是我个人建议了解一下即可,大概浏览一下,留意我代码加了1,2,3 这3个重点的地方即可。
# TransactionExecutorHelper// 定义需要经过的生命周期路径,长度为6(毕竟一共也才7个生命周期)@ActivityLifecycleItem.LifecycleStateprivate IntArray mLifecycleSequence = new IntArray(6);// start :开始的生命周期状态// finish :结束的生命周期状态// excludeLastState :是否移除最后一个状态public IntArray getLifecyclePath(int start, int finish, boolean excludeLastState) {// 如果开始状态或结束状态未定义,则抛出异常if (start == UNDEFINED || finish == UNDEFINED) {throw new IllegalArgumentException("Can't resolve lifecycle path for undefined state");}// 如果开始状态或结束状态是ON_RESTART,则抛出异常,因为在生命周期中不能以此状态开始或结束if (start == ON_RESTART || finish == ON_RESTART) {throw new IllegalArgumentException("Can't start or finish in intermittent RESTART state");}// 如果结束状态为PRE_ON_CREATE且开始状态不等于结束状态,则抛出异常,只能从预创建状态开始if (finish == PRE_ON_CREATE && start != finish) {throw new IllegalArgumentException("Can only start in pre-onCreate state");}// 重点* 1. 清空用于存储生命周期状态变更序列的集合mLifecycleSequence.clear();// 重点* 2. 分情况计算生命周期状态变更路径 (正常场景)if (finish >= start) {// 如果结束状态大于等于开始状态if (start == ON_START && finish == ON_STOP) {// 特殊情况:从开始到停止状态,无需经过暂停和恢复状态mLifecycleSequence.add(ON_STOP);} else {// 重点* 3. 普通情况:直接将中间的所有状态加入序列 (正常场景)for (int i = start + 1; i <= finish; i++) {mLifecycleSequence.add(i);}}} else { // 结束状态小于开始状态,不能简单地向下循环if (start == ON_PAUSE && finish == ON_RESUME) {// 特殊情况:从暂停直接到恢复状态mLifecycleSequence.add(ON_RESUME);} else if (start <= ON_STOP && finish >= ON_START) {// 开始状态在ON_STOP之前且结束状态在ON_START之后的情况// 先转为停止状态for (int i = start + 1; i <= ON_STOP; i++) {// 添加mLifecycleSequence.add(i);}// 添加mLifecycleSequence.add(ON_RESTART);// 再转到指定结束状态for (int i = ON_START; i <= finish; i++) {mLifecycleSequence.add(i);}} else {// 其他情况:需要重新启动并转到指定状态// 先转到销毁状态for (int i = start + 1; i <= ON_DESTROY; i++) {// 添加mLifecycleSequence.add(i);}// 再转到指定结束状态for (int i = ON_CREATE; i <= finish; i++) {// 添加mLifecycleSequence.add(i);}}}// 如果要求排除最后一个状态并且生命周期序列不为空,则移除最后一个状态if (excludeLastState && mLifecycleSequence.size() != 0) {mLifecycleSequence.remove(mLifecycleSequence.size() - 1);}// 返回计算好的生命周期状态变更序列return mLifecycleSequence;}
根据当前分析的场景,这个方法执行以下3步:
-
- 清除集合的数据,避免有脏数据影响结果
-
- 当前第一个参数是 ON_CREATE(1), 第二个参数定义在 ResumeActivityItem 下,返回值是 ON_RESUME(3),满足finish >= start的条件,所以进if语句
-
- 走 else 逻辑,最终 mLifecycleSequence 下也就一个元素 : 2 ,返回返回
2.2 performLifecycleSequence 切换Activity的生命周期
上一小节计算出需要执行的生命周期路径后,现在就要开始应用了。
# TransactionExecutor// 实际执行在 ActiviThreadprivate ClientTransactionHandler mTransactionHandler;// 构造方法赋值public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {mTransactionHandler = clientTransactionHandler;}private void performLifecycleSequence(ActivityClientRecord r, IntArray path,ClientTransaction transaction) {// 当前场景就1个元素final int size = path.size();// 开始遍历for (int i = 0, state; i < size; i++) {// 获取到状态,当前就1个元素:ON_START( 2)state = path.get(i);// 打印logif (DEBUG_RESOLVER) {Slog.d(TAG, tId(transaction) + "Transitioning activity: "+ getShortActivityName(r.token, mTransactionHandler)+ " to state: " + getStateName(state));}switch (state) {......case ON_START:mTransactionHandler.handleStartActivity(r, mPendingActions,null /* activityOptions */);break;......} }}
mTransactionHandler 在构造 TransactionExecutor 的构造方法赋值,创建对象的地方在 ActivityThread 中,传递的参数是 this,而 ActivityThread 是 ClientTransactionHandler 的子类,也就是说 mTransactionHandler 真正的实现还是在 ActivityThread。
# ActivityThread@Overridepublic void handleStartActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, ActivityOptions activityOptions) {// 拿到 Activityfinal Activity activity = r.activity;......// Start// 重点* 1. 执行onStartactivity.performStart("handleStartActivity");// 2. 更新对应的状态r.setState(ON_START);......// 重点* 3. 更新可见性,参数为trueupdateVisibility(r, true /* show */);mSomeActivitiesChanged = true;......}
一共处理了3件事,其中设置状态的逻辑之前看过了,看看另外2个重点流程。
2.3 onStart 流程
# Activityfinal void performStart(String reason) {......// 执行onStartmInstrumentation.callActivityOnStart(this);// wm_on_start_calledEventLogTags.writeWmOnStartCalled(mIdent, getComponentName().getClassName(), reason);......// Fragment 处理mFragments.dispatchStart();......}# Instrumentationpublic void callActivityOnStart(Activity activity) {activity.onStart();}
到这里 Activity 的 onStart 就执行了。
2.4 设置 View 可见
上一小节先执行到 onStart ,然后会设置 View 的可见性, 看一下具体代码
# ActivityThreadprivate void updateVisibility(ActivityClientRecord r, boolean show) {// 拿到DecorViewView v = r.activity.mDecor;if (v != null) {if (show) {if (!r.activity.mVisibleFromServer) {r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {// 设置 View 可见 (当前逻辑)r.activity.makeVisible();}}} else {if (r.activity.mVisibleFromServer) {r.activity.mVisibleFromServer = false;mNumVisibleActivities--;// 隐藏Viewv.setVisibility(View.INVISIBLE);}}}}
当前是 onStart 逻辑,也看到了方法传递的参数是 true,说明要设置可见,所以会执行 Activity::makeVisible 逻辑。
# Activityvoid makeVisible() {if (!mWindowAdded) { // 之前setView时已置位trueViewManager wm = getWindowManager();wm.addView(mDecor, getWindow().getAttributes());mWindowAdded = true;}// 设置可见mDecor.setVisibility(View.VISIBLE);}
2.5 onStart 小结
启动一个Activity 执行到 onStart 流程的分析就结束了,完整调用链如下:
TransactionExecutor::cycleToPathTransactionExecutorHelper::getLifecyclePathTransactionExecutor::performLifecycleSequenceClientTransactionHandler::handleStartActivityActivityThread::handleStartActivityActivity::performStart -- onStartInstrumentation::callActivityOnStartActivity::onStartActivityClientRecord::setState -- 状态设置为 ON_STARTActivityThread::updateVisibility -- 更新View可见性Activity::makeVisibleView::setVisibility -- VISIBLE
如果是按多任务键(Recent)再回到 Activity 是会执行 ActivityRecord::makeActiveIfNeeded 来构建 StartActivityItem 事务处理 onStart 流程,但是后续的逻辑还是一样的
我们知道 onStart 和 onStop 是成对的, 那 onStart 会执行 View::setVisibility 设置 View 可见,那相对的在 onStop 流程是不是就会 设置 View 不可见呢?
这个疑问留到下一篇 onStop 流程解答。
当前还是继续看 onResume 的执行
3. onResume
onResume 对应事务为 ResumeActivityItem
# ResumeActivityItem@Overridepublic void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {// TraceTrace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");// 应用端处理client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,"RESUME_ACTIVITY");Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}@Overridepublic void postExecute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {// TODO(lifecycler): Use interface callback instead of actual implementation.ActivityClient.getInstance().activityResumed(token, client.isHandleSplashScreenExit(token));}@Overridepublic int getTargetState() {return ON_RESUME;}
调用链如下:
ResumeActivityItem::executeActivityThread::handleResumeActivityActivityThread::performResumeActivity Activity::performResume Instrumentation::callActivityOnResumeActivity::onResume -- onResumeActivityClientRecord::setState -- ON_RESUMEWindowManagerImpl::addView -- 创建ViewRootImplWindowManagerGlobal::addView ViewRootImpl::setView -- 与WMS通信与WMS通信触发窗口的显示逻辑
开始撸代码。
# ActivityThreadpublic void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {......// 触发onResumeif (!performResumeActivity(r, finalStateRequest, reason)) {return;}......// 拿到activityfinal Activity a = r.activity;......if (r.window == null && !a.mFinished && willBeVisible) {// 将本地的window设置到activityRecord中r.window = r.activity.getWindow();// 获取DecorViewView decor = r.window.getDecorView();// 设置不可见 在后面调用Activity::makeVisible会设为可见decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();// 获取参数WindowManager.LayoutParams l = r.window.getAttributes();// DecorView设置给Activitya.mDecor = decor;// 设置Activity的windowType,注意这个type,才是应用的窗口类型l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;......if (a.mVisibleFromClient) {if (!a.mWindowAdded) {// 重点:执行addView,并设置mWindowAdded=truea.mWindowAdded = true;wm.addView(decor, l);} else {a.onWindowAttributesChanged(l);}}} else if (!willBeVisible) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");r.hideForNow = true;}......r.nextIdle = mNewActivities;mNewActivities = r;// stop 逻辑的触发if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);Looper.myQueue().addIdleHandler(new Idler());}
当前分析 onResume 生命周期,所以只看 performResumeActivity 方法就好。
# ActivityThread@VisibleForTestingpublic boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,String reason) {// logif (localLOGV) {Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);}......// 触发 onResumer.activity.performResume(r.startsNotResumed, reason);// 设置状态r.setState(ON_RESUME);......}
# Activityfinal void performResume(boolean followedByPause, String reason) {// traceif (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performResume:"+ mComponent.getClassName());}......// 主流程mInstrumentation.callActivityOnResume(this);// wm_on_resume_calledEventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason);......// Fragments 处理mFragments.dispatchResume();......}
流程和其他的一样,也是先通过 Instrumentation 然后又回到 Activity 处理,然后打印另一个 events 日志。
# Instrumentationpublic void callActivityOnResume(Activity activity) {activity.mResumed = true;activity.onResume();}
4. 总结
SourceActivity 在启动过程中会执行的3个生命周期已经分析完了,当前分析的场景下有以下几个点:
-
- 这3个生命周期的执行的连续的,
-
- onStart 原来这个场景下不是通过事务执行的
-
- 知道了 Activity 生命周期事务跨进程处理方式
-
- DecorView 的可见性是在 onStart 设置的
-
- 执行 onResume 的时候会触发窗口的添加显示,从严格意义上说,执行 onResume 的时候并不意味着手机屏幕上就有UI数据了。(但是不那么严谨思考的话,正常情况下,onResume 执行了差不多窗口也就显示了)
关于 events 日志的整理如下:
-
- wm_restart_activity 的触发在 ActivityTaskSupervisor::realStartActivityLocked 方法构建2个事务的时候,表示 SystemService 端要真正触发 TargetActivity 启动
-
- wm_on_create_called 的触发在 Activity::performCreate 方法,表示TargetActivity端执行 onCreate
-
- wm_on_start_called 的触发在 Activity::performStart 方法,表示TargetActivity端执行 onStart
-
- wm_on_resume_called 的触发在 Activity::performResume 方法,表示TargetActivity端执行 onResume
相关文章:
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。 – 服装…...
如何在电脑上浏览手机界面
联想浏览器中,点击右键-》检查,进入开发者工具: 点击如上,红色框框选中的手机浏览模式即可。...
国产RISC-V案例分享,基于全志T113-i异构多核平台!
RISC-V核心优势 全志T113-i是一款双核Cortex-A7@1.2GHz国产工业级处理器平台,并内置玄铁C906 RISC-V和HiFi4 DSP双副核心,可流畅运行Linux系统与Qt界面,并已适配OpenWRT系统、Docker容器技术。 而其中的RISC-V属于超高能效副核心,主频高达1008MHz,标配内存管理单元,可运…...
Day(16)--File
File File对象就是表示一个路径,可以是文件路径,也可以是文件夹的路径 这个路径可以是存在的,也允许是不存在的 常见的方法 public File(String pathname);//根据文件路径创建文件对象 public File(String parent,String child);//根据父路…...
Axios入门使用
文章目录 Axios入门使用一、引言二、Axios的安装与配置1、安装Axios2、创建Axios实例 三、发送HTTP请求1、GET请求2、POST请求3、并发请求 四、配置和拦截器1、配置默认值2、拦截器 五、错误处理和取消请求1、错误处理2、取消请求 四、总结 Axios入门使用 一、引言 随着前端技…...
大数据实时数仓Hologres(四):基于Flink+Hologres搭建实时数仓
文章目录 基于Flink+Hologres搭建实时数仓 一、使用示例 二、方案架构 1、架构优势 2、Hologres核心优势 三、实践场景 四、项目准备 1、创建阿里云账号AccessKey 2、准备MySQL数据源 五、构建实时数仓编辑 1、管理元数据 2、构建ODS层 2.1、创建CDAS同步作业O…...
关于HTML 案例_个人简历展示02
展示效果 用table进行布局label 标签进行关联 例如:点姓名就可以到text中去填写内容 input的使用 text 文本框radio 单选框select与option 选择框checkbox 复选框 textareaul与li 无序列表文中图片是本地的 链接: 图片下载地址 代码 <!DOCTYPE html> <…...
Windows 11 24H2 v26100.1742 官方简体中文版
Windows 11 24H2是微软最新推出的操作系统更新,其在人工智能(AI)领域的创新为用户带来了显著的体验提升。该版本的一大亮点是AI Copilot,它能够智能地根据剪贴板内容调整操作上下文菜单,实现更智能化的交互。 此外&…...
【AIGC半月报】AIGC大模型启元:2024.10(上)
【AIGC半月报】AIGC大模型启元:2024.10(上) (1) YOLO11(Ultralytics新作) (1) YOLO11(Ultralytics新作) 2024.10.01 Ultralytics在 YOLO Vision 2024 活动上宣布发布其新的计算机视觉模型 YOLO…...
Codeforces Beta Round 14 (Div. 2) E. Camels (DP)
题目 Bob likes to draw camels: with a single hump, two humps, three humps, etc. He draws a camel by connecting points on a coordinate plane. Now he’s drawing camels with t humps, representing them as polylines in the plane. Each polyline consists of n ve…...
CSID-GAN:基于生成对抗网络的定制风格室内平面设计框架论文阅读
CSID-GAN: A Customized Style Interior Floor Plan Design Framework Based on Generative Adversarial Network 摘要前言II. CSID-GAN METHODA. Overall FrameworkB. Algorithm and Loss Function III. DATASETS AND EVALUATION METRICSA. DatasetsB. Evaluation Metrics IV.…...
02SQLite
文章目录 索引创建索引删除索引索引优点及缺点?避免使用索引 视图创建视图删除视图 事务事务控制命令通过事务方式对数据库进行访问优势: 索引 创建索引 索引(Index)是一种特殊查找表,数据库搜索引擎用来加速数据检索…...
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
在线学籍管理平台系统 目录 基于SpringbootVUE的在线学籍管理平台系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…...
JDBC编程
前言: 你是否见过用Java连接数据库的操作,对没错,今天我们要讲的就是这个“高级”操作,做好准备全程高速。 API: 什么是API?我喜欢先把它的全称说一下:Application Programming Interface。简…...
Python : 类变量、静态方法、类方法
文章目录 前言1 类变量(Java静态变量)2 Python中的静态方法(使用 @staticmethod 装饰器声明)3 类方法(使用 @classmethod 装饰器声明)4 静态方法和类方法的区别前言 学完Java过后,对python中有了一些疑惑。Java中有static修饰的静态变量和静态方法这两个很用用的知识点…...
大厂笔试现已经禁用本地IDE怎么看
如果我说本来面试做题这种事情就是反人类你相信吗? 这个罪恶的源头就是 Google,说是为了选择高素质的计算机编程水平的人才,然后把面试就变成了考试,最大的受益者当然是印度人了。 当把一个考察过程变成标准化的考试过程&#x…...
【PostgreSQL】入门篇——如何创建、删除和管理数据库及其用户,包括权限设置和角色管理
PostgreSQL 数据库及用户管理 1. 创建数据库 1.1 使用 SQL 命令创建数据库 在 PostgreSQL 中,可以使用 CREATE DATABASE 命令来创建数据库。以下是基本语法: CREATE DATABASE database_name;示例: CREATE DATABASE my_database;1.2 使用…...
网络安全:保护数字时代的堡垒
网络安全:保护数字时代的堡垒 引言: 在数字化时代,网络安全的重要性日益凸显。它不仅关系到个人隐私保护,还涉及国家安全和经济发展。随着技术的发展,网络安全的威胁也在不断进化,从个人设备到企业网络&am…...
【rCore OS 开源操作系统】Rust 字符串(可变字符串String与字符串切片str)
【rCore OS 开源操作系统】Rust 语法详解: Strings 前言 这次涉及到的题目相对来说比较有深度,涉及到 Rust 新手们容易困惑的点。 这一次在直接开始做题之前,先来学习下字符串相关的知识。 Rust 的字符串 Rust中“字符串”这个概念涉及多种类型&…...
远程过程调用RPC知识科普
文章目录 什么是RPCRPC的基本原理RPC的应用场景RPC的优势常见的RPC框架 常见的RPC协议1. gRPC2. Apache Thrift3. Dubbo4. JSON-RPC5. XML-RPC6. SOAP springboot环境下常用的RPC框架使用1. Apache Dubbo2. Apache Thrift3. gRPC4. Spring Cloud OpenFeign 什么是RPC RPC&…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...
