【Android 源码分析】Activity生命周期之onStop-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

当前为“onStop”第二篇,整个流程分为3步:

    1. addToStopping 流程,将应用添加进需要stop的列表 – system_service进程处理
    1. stopIfPossible 流程,也就是开始执行stop – system_service进程处理
    1. 应用端处理stop流程 – 应用进程处理

前面个都是system_service进程处理的,第三步是在 SourceActivity 的应用进程处理。

1. 第二步:stopIfPossible 开始执行stop

根据上一小节后的2个线索,得到以下信息:

    1. “wm_stop_activity”的打印在 ActivityRecord::stopIfPossible 方法,并且打印log后就构建了 StopActivityItem
    1. 在 ActivityTaskSupervisor::activityIdleInternal 方法内有堆栈打印,日志如下:
ActivityTaskManager: activityIdleInternal:
Callers=com.android.server.wm.ActivityClientController.activityIdle:142android.app.IActivityClientController$Stub.onTransact:550com.android.server.wm.ActivityClientController.onTransact:125android.os.Binder.execTransactInternal:1285 

根据这2点信息其实就已经可以获得到这么一个完整的调用链了:

ActivityClientController::activityIdleActivityTaskSupervisor::activityIdleInternalActivityTaskSupervisor::processStoppingAndFinishingActivitiesActivityRecord::stopIfPossibleActivityRecord::setState  -- 设置为 STOPPINGStopActivityItem.obtain -- 构建触发StopActivityItem

后面的逻辑晚点再看,先分析 ActivityClientController::activityIdle 是怎么调用过来的。

1.1 ActivityClientController::activityIdle 的触发逻辑

TargetActivity 执行 onResume 的逻辑是在应用端是由 ActivityThread::handleResumeActivity方法开始的,而这个方法最后添加了一个 Idler 到 IdleHandler中,这个 Idler 就是触发
ActivityClientController::activityIdle 的地方。

整个AOSP中调用 ActivityClientController::activityIdle 的地方只有2个,根据log定位是在 ActivityThread 下的内部类 Idler 中。

# ActivityThreadpublic void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {......// 触发 TargetActivity的 onResumeif (!performResumeActivity(r, finalStateRequest, reason)) {return;}......// 拿到activityfinal Activity a = r.activity;......//setView 逻辑r.nextIdle = mNewActivities;mNewActivities = r;//触发SourceActivity 的onStop if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);Looper.myQueue().addIdleHandler(new Idler());}

根据调用顺序:先触发 TargetActivity的 onResume,再触发 SourceActivity 的 onStop 。

这一点和实际的log打印也是对上了,接下来就看看 Idler() 是怎么执行的了。

addIdleHandler 方法会把一个 IdleHandler 添加到先洗队列的 mIdleHandlers 列表,这里是 Handler 知识点下关于 IdleHandler 的知识,不知道的可以搜一下相关的文章看看。
IdleHandler 的特效就是会在 CPU 空闲的时候才会执行相关任务。

1.1.1 Idler

Idler 是 ActivityThread 的内部类

# ActivityThreadprivate class Idler implements MessageQueue.IdleHandler {@Overridepublic final boolean queueIdle() {ActivityClientRecord a = mNewActivities;......if (a != null) {mNewActivities = null;final ActivityClient ac = ActivityClient.getInstance();ActivityClientRecord prev;do {// 日志if (localLOGV) Slog.v(TAG, "Reporting idle of " + a +" finished=" +(a.activity != null && a.activity.mFinished));if (a.activity != null && !a.activity.mFinished) {// 重点* 执行 ActivityClientController::activityIdleac.activityIdle(a.token, a.createdConfig, stopProfiling);a.createdConfig = null;}prev = a;a = a.nextIdle;prev.nextIdle = null;} while (a != null);}if (stopProfiling) {mProfiler.stopProfiling();}return false;}}

这里的重点就是在主线程空闲的时候,就会执行 queueIdle() 方法,进而触发 SourceActivity 的 StopActivityItem 事务构建。
在日志中搜索添加 Idler 的日志和 queueIdle 方法执行的日志信息如下:

Line 12732: 04-01 20:50:30.891 24294 24294 V ActivityThread: Scheduling idle handler for ActivityRecord{b7ece46 token=android.os.BinderProxy@1fee9be {com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity}}Line 19074: 04-01 20:50:31.170 24294 24294 V ActivityThread: Reporting idle of ActivityRecord{b7ece46 token=android.os.BinderProxy@1fee9be {com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity}} finished=false

可以看到时间上确实还是有很大间隔的。

1.2 ActivityClientController::activityIdle 的处理

上面看到了是如何调用过来的,现在看一下后续的调用逻辑

# ActivityClientController@Overridepublic void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {final long origId = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {// TraceTrace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");final ActivityRecord r = ActivityRecord.forTokenLocked(token);if (r == null) {return;}// 重点逻辑mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,false /* processPausingActivities */, config);......}} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);Binder.restoreCallingIdentity(origId);}}

直接调用了 ActivityTaskSupervisor::activityIdleInternal 方法,这个方法在签名 SourceActivity 的 addToStopping 流程已经看过一次,现在条件不同执行的逻辑也不一样,再看一下这个方法。

# ActivityTaskSupervisorvoid activityIdleInternal(ActivityRecord r, boolean fromTimeout,boolean processPausingActivities, Configuration config) {// 重点* 1 logif (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);// 重点* 2. ActivityRecord 不为null才执行内部逻辑if (r != null) {// 重点* 3. logif (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternal: Callers="+ Debug.getCallers(4));......}......// Atomically retrieve all of the other things to do. 原子检索所有其他要做的事情// 重点* 4. 看方法名是处理 停止和finish的Activity辑在这里processStoppingAndFinishingActivities(r, processPausingActivities, "idle");if (DEBUG_IDLE) {// 重点* 5. log Slogf.i(TAG, "activityIdleInternal(): r=%s, mStartingUsers=%s", r, mStartingUsers);}......}

这一次因为参数 r 不为null,所以还会打印“重点* 3”处的log,然后进入processStoppingAndFinishingActivities 方法。

1.2.1 再看 processStoppingAndFinishingActivities 逻辑(真正执行)

# ActivityTaskSupervisor/*** Processes the activities to be stopped or destroyed. This should be called when the resumed* 处理要停止或销毁的Activity。这应该在resumed时调用* activities are idle or drawn.*/private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,boolean processPausingActivities, String reason) {// 准备要执行 Stop 的Activity 集合 ArrayList<ActivityRecord> readyToStopActivities = null;// 重点 * 1. 遍历mStoppingActivitiesfor (int i = mStoppingActivities.size() - 1; i >= 0; --i) {// 获取到ActivityRecord (当前分析场景就1个)final ActivityRecord s = mStoppingActivities.get(i);final boolean animating = s.isAnimating(TRANSITION | PARENTS,ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)|| s.inTransition();// 日志ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "+ "finishing=%s", s, s.nowVisible, animating, s.finishing);// 条件满足才执行if (!animating || mService.mShuttingDown) {......// 打印 准备stop的logProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);if (readyToStopActivities == null) {readyToStopActivities = new ArrayList<>();}// 重点 * 2. 添加进集合readyToStopActivities.add(s);// 从集合中移除mStoppingActivities.remove(i);}}// 重点 * 3. 遍历readyToStopActivitiesfinal int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();for (int i = 0; i < numReadyStops; i++) {final ActivityRecord r = readyToStopActivities.get(i);// 检查该ActivityRecord对象是否在历史记录中。  if (r.isInHistory()) {// 如果该ActivityRecord对象正在结束(可能是用户或系统触发的结束操作)。if (r.finishing) {// TODO(b/137329632): Wait for idle of the right activity, not just any.r.destroyIfPossible(reason);} else {// 重点* 4. 如果ActivityRecord对象不在结束状态,则尝试停止它r.stopIfPossible();}}}......}

这个时候再看这个方法就能理解方法上面的注释了:This should be called when the resumed 。

    1. 遍历 mStoppingActivities 集合,这个集合里是有当前场景的唯一元素是 SourceActivity (当前是QuickstepLauncher)。

这一次的打印如下:

WindowManager: Stopping ActivityRecord{f40797d u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t20}: nowVisible=false animating=false finishing=false  mShuttingDown=false
    1. 由于“animating=false”所以会执行 if 内部语句,把 SourceActivity 添加到 readyToStopActivities 集合中。

并打印ProtoLog

WindowManager: Ready to stop: ActivityRecord{f40797d u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t20}
    1. 遍历 readyToStopActivities 下的元素,然后执行 ActivityRecord::stopIfPossible 方法

processStoppingAndFinishingActivities 方法是处理 Activity 的核心方法,他的触发点当前文章就分析到了2个,另外肯定还有其他的调用逻辑
比如我将 ActivityThread::handleResumeActivity 方法下最后一行将 Idler 添加进 IdleHandler 的代码删了,本以为就不会执行 SourceActivity 的 onStop 了,没想到还会通过发送一个 PROCESS_STOPPING_AND_FINISHING_MSG 消息来触发 processStoppingAndFinishingActivities 方法的执行。
毕竟 Activity 生命周期是基础代码,google这快代码的健壮性肯定是考虑周全的。

1.3 真正触发StopActivityItem构建的地方 ActivityRecord::stopIfPossible

# ActivityRecordvoid stopIfPossible() {// logif (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);final Task rootTask = getRootTask();......try {stopped = false;// 关键log (这里还是即将 stop)ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);......// 重点* 1. 设置Activity的状态为STOPPING,原因为"stopIfPossible"setState(STOPPING, "stopIfPossible");if (DEBUG_VISIBILITY) {// logSlog.v(TAG_VISIBILITY, "Stopping:" + this);}// events日志 :wm_stop_activity: [0,198530468,com.example.myapplication/.MainActivity]EventLogTags.writeWmStopActivity(mUserId, System.identityHashCode(this), shortComponentName);// 重点* 2. 构建执行 Stop 事务mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,StopActivityItem.obtain(configChangeFlags));mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);}}

就做了2件事:

    1. 设置状态为 STOPPING
    1. 构建执行 StopActivityItem

不过这里有很多log,跟踪问题的时候可以关注一下。

2. SystemService 端小结

当前冷启动场景下,SourceActivity 的onStop处理,SystemService 端其实就做了2件事。

    1. 把 SourceActivity 添加到 ActivityTaskSupervisor 类下的 mStoppingActivities 集合中,这一步我成为“addToStopping 流程”,对应的events日志为:“wm_add_to_stopping”
      这一步的执行也毕竟早,在 SourceActivity 执行完 Pause 流程就触发了。
    1. 执行 ActivityTaskSupervisor::processStoppingAndFinishingActivities 方法,将 mStoppingActivities 集合下的 ActivityRecord 取出,执行 ActivityRecord::stopIfPossible 方法,在这里构建执行 StopActivityItem 。

当前分析的是常见流程的调用逻辑,还有一些其他逻辑也会触发onStop,但是目前看来都会执行 ActivityTaskSupervisor::processStoppingAndFinishingActivities 方法,所以以后遇到相关问题可以关注一下该方法的执行。

到这里 SystemService 的处理就结束了,后续流程就在应用端了。

那后续就是应用进程执行 Stop 的流程了。

3.应用端 onStop 处理

应用端的处理就相对简单了,先看一下 StopActivityItem 的定义

# StopActivityItem@Overridepublic void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");//  触发应用进程stopclient.handleStopActivity(r, mConfigChanges, pendingActions,true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}

具体的实现肯定是在ActivityThread中了,整理的调用链如下:

StopActivityItem::executeClientTransactionHandler::handleStopActivityActivityThread::handleStopActivityActivityThread::performStopActivityInnerActivityThread::callActivityOnStopActivityThread::callActivityOnSaveInstanceState  -- OnSaveInstanceState 逻辑Activity::performStopInstrumentation.callActivityOnStopActivity::onStop        -- 生命周期ActivityThread::updateVisibility        -- 处理View不可见

开始撸代码

# ActivityThread@Overridepublic void handleStopActivity(ActivityClientRecord r, int configChanges,PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {r.activity.mConfigChangeFlags |= configChanges;final StopInfo stopInfo = new StopInfo();// 重点* 1. onStop 流程performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest,reason);if (localLOGV) Slog.v(TAG, "Finishing stop of " + r + ": win=" + r.window);// 重点* 2. 更新Activity的可见性状态为不可见updateVisibility(r, false);......}

这里分为2步逻辑,先执行 onStop ,再处理 View 可见性。

3.1 onStop 执行逻辑

# ActivityThreadprivate void performStopActivityInner(ActivityClientRecord r, StopInfo info,boolean saveState, boolean finalStateRequest, String reason) {......// One must first be paused before stopped... // 1. 必须先执行 pause,才可以 stop。performPauseActivityIfNeeded(r, reason);......// 2. 主流程callActivityOnStop(r, saveState, reason);}

这个方法做了2件事:

    1. 必须先执行 pause,才可以 stop,所以需要执行一下 performPauseActivityIfNeeded 方法,不过正常逻辑执行到这,已经是pause状态了,所以这个方法内部进去就会return。
# ActivityThreadprivate void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {if (r.paused) {// You are already paused silly...return;}......}
    1. 继续执行主流程,触发Activity的 onStop 回调
# ActivityThreadprivate void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {// Before P onSaveInstanceState was called before onStop, starting with P it's// called after. Before Honeycomb state was always saved before onPause.final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null&& !r.isPreHoneycomb();final boolean isPreP = r.isPreP();if (shouldSaveState && isPreP) {// 重点* 1. callActivityOnSaveInstanceStatecallActivityOnSaveInstanceState(r);}try {// 重点* 2. onStop流程r.activity.performStop(r.mPreserveWindow, reason);} ......if (shouldSaveState && !isPreP) {// 重点* 1. callActivityOnSaveInstanceStatecallActivityOnSaveInstanceState(r);}}
    1. 可以看到2次执行了 onSaveInstanceState 回调,这个可以在【Android 11源码分析】看相关的
    1. 是本次分析的主流程,已经执行到Activity的方法了,里生命周期onStop不远了
# Activityprivate Instrumentation mInstrumentation;final void performStop(boolean preserveWindow, String reason) {......// Fragment的处理mFragments.dispatchStop();mCalled = false;// 回调onStop流程mInstrumentation.callActivityOnStop(this);......}

Instrumentation 这个类中处理了所有的Activity生命周期回调。

# Instrumentationpublic void callActivityOnStop(Activity activity) {// onStopactivity.onStop();}

3.2 Stop 处理View的可见性

# ActivityThreadprivate void updateVisibility(ActivityClientRecord r, boolean show) {// 拿到对应Activity的 DecorViewView v = r.activity.mDecor;if (v != null) {if (show) {// 如果Activity当前在服务器端不可见, 就需要处理成可见if (!r.activity.mVisibleFromServer) {r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {// 设置可见r.activity.makeVisible();}}} else {// 如果Activity当前在服务器端可见, 就需要处理成不可见if (r.activity.mVisibleFromServer) {r.activity.mVisibleFromServer = false;mNumVisibleActivities--;// 影藏Viewv.setVisibility(View.INVISIBLE);}}}}

所以经常会有人执行了onStop 才是真正的Activity不可见,原因就是onStop的逻辑会把 View设置为不可见,间接的Activity也就不可见了。

4. 总结

当前只是以桌面冷启动应用的场景来分析桌面的 onStop 流程,整个流程分析完对 onStop 流程也有了一个比较完整的了解,但是当前分析的调用流程并不能代表所有场景。具体情况还是需要具体分析,比如应用内启动 Activity 的调用链肯定和当前是有别的,但是无论怎么样,2个主流程还是要执行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/55767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息安全工程师(28)机房安全分析与防护

前言 机房安全分析与防护是一个复杂而细致的过程&#xff0c;涉及到物理安全、环境控制、电力供应、数据安全、设备管理、人员管理以及紧急预案等多个方面。 一、机房安全分析 1. 物理安全威胁 非法入侵&#xff1a;未经授权的人员可能通过门窗、通风口等进入机房&#xff0c;…

【LeetCode】每日一题 2024_10_10 优质数对的总数 I(暴力/哈希)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;优质数对的总数 I 代码与解题思路 简单题先暴力~ 直接对着题意模拟即可&#xff0c;力扣上只要是标着简单标签的题目&#xff0c;不用犹豫&#xff0c;直接对他使用暴力吧&#xff01; …

亮度(luminance)

亮度&#xff08;luminance&#xff09;的单位是坎德拉每平方米&#xff08;cd/m&#xff09;。它是用来描述光源或物体表面发出的光在某个方向上的亮度程度。亮度可以简单理解为人眼感知的物体表面在某一特定方向上发出的光强。 亮度的理解&#xff1a; 亮度的概念&#xff…

LabVIEW混合控制器质量检测

随着工业自动化水平的提高&#xff0c;对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域&#xff0c;传统的质量检测方法已无法满足现代工业的高要求。因此&#xff0c;开发一套自动化、精确、可扩展的混合控制器质量检测平台成…

【Linux】常用系统命令

Linux 系统中有许多常用的命令&#xff0c;适用于不同的任务和场景。以下是一些基础且常用的 Linux 命令&#xff1a; 1. **文件和目录操作** - ls&#xff1a;列出目录内容。 - cd&#xff1a;改变当前目录。 - pwd&#xff1a;打印当前工作目录。 - mkdir&#…

Redis 数据类型string(字符串)

目录 1 基本特性 2 主要操作命令 2.1 设置键值 2.1.1 SET key value [EX seconds] [PX milliseconds] [NX|XX] 2.1.2 MSET key value [key value ...] 2.1.3 SETEX key seconds value 2.1.4 PSETEX key milliseconds value 2.1.5 APPEND key value 2.2 获取键值 …

Pikachu-Cross-Site Scripting-xss盲打

xss盲打&#xff0c;不是一种漏洞类型&#xff0c;而是一个攻击场景&#xff1b;在前端、或者在当前页面是看不到攻击结果&#xff1b;而是在后端、在别的页面才看到结果。 登陆后台&#xff0c;查看结果&#xff1b;

Extreme Compression of Large Language Models via Additive Quantization阅读

文章目录 Abstract1. Introduction2. Background & Related Work2.1. LLM量化2.2. 最近邻搜索的量化 3.AQLM:Additive Quantization for LLMs3.1. 概述3.1.0 补充**步骤说明****举例说明** 3.2. 阶段1&#xff1a;代码的波束搜索3.3. 阶段2&#xff1a;码本更新3.4. 阶段3&…

Qt Creator 通过python解释器调用*.py

全是看了大佬们的帖子&#xff0c;结合chatGPT才揉出来。在此做个记录。 安装python在Qt Creator *.pro 文件中配置好环境来个简单的example.py调用代码安装pip添加opencv等库调用包含了opencv库的py代码成功 *.pro配置&#xff1a; INCLUDEPATH C:\Users\xuanm\AppData\Lo…

wordpress在页面中调用另外一个页面的内容

在WordPress中&#xff0c;一个页面调用另一个页面的内容通常不是WordPress设计的直接功能&#xff0c;因为WordPress的页面和内容通常是独立管理的。不过&#xff0c;你可以通过几种方法来实现这一需求&#xff1a; 1. 使用WordPress的短代码(Shortcodes) 你可以创建一个自定…

操作系统中的并发控制——使用条件变量同步

本期主题&#xff1a; 操作系统中的并发控制&#xff0c;条件变量 往期链接&#xff1a; linux设备驱动中的并发操作系统中的多线程问题——原子操作、自旋锁的底层实现操作系统并发控制——使用互斥锁实现同步 操作系统并发控制之条件变量同步 1. 问题描述2. 条件变量的API讲…

Netty的线程模型

Netty的线程模型是其核心特性之一&#xff0c;主要包括以下几个方面&#xff1a; 线程模型概述 作用与重要性&#xff1a;线程模型决定了代码在操作系统、编程语言和框架中的执行方式&#xff0c;对于处理多线程相关的问题至关重要。在网络编程中&#xff0c;合理的线程模型可…

云栖实录 | Hologres3.0全新升级:一体化实时湖仓平台

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 姜伟华 | 阿里云智能集团资深技术专家、Hologres 负责人 丁 烨 | 阿里云智能集团产品专家、Hologres 产品负责人 活动&#xff1a; 2024 云栖大会 - 商用大数据计算与分析平台论…

Python中的数据可视化:从入门到进阶

数据可视化是数据分析和科学计算中的重要环节&#xff0c;它通过图形化的方式呈现数据&#xff0c;使复杂的统计信息变得直观易懂。Python提供了多种强大的库来支持数据可视化&#xff0c;如Matplotlib、Seaborn、Plotly等。本文将从基础到进阶&#xff0c;详细介绍如何使用这些…

[单master节点k8s部署]31.ceph分布式存储(二)

Ceph配置 Ceph集群通常是一个独立的存储集群&#xff0c;可以部署在 Kubernetes 集群之外。Ceph 提供分布式存储服务&#xff0c;能够通过 RADOS、CephFS、RBD&#xff08;块存储&#xff09;、和 RGW&#xff08;对象存储&#xff09;等方式与 Kubernetes 集成。即使 Ceph 部…

逼近理论及应用精解【9】

文章目录 全卷积模型定义数学原理与公式架构典型结构应用优点挑战例题 ANNSENet&#xff08;Squeeze-and-Excitation Networks&#xff09;定义数学原理与公式计算定理架构例子例题 ResNet&#xff08;残差网络&#xff09;定义数学原理与公式计算定理算法过程架构例子例题 参考…

PostgreSQL学习笔记五:数据库基本操作

在 PostgreSQL 中&#xff0c;您可以执行一系列基础操作来管理数据库、备份和恢复数据。以下是一些常用的命令和步骤&#xff1a; 创建数据库 使用以下命令创建新数据库&#xff1a; CREATE DATABASE database_name;您也可以在创建时指定数据库所有者和其他参数&#xff1a;…

基于深度学习的手势控制模型

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 1. 项目简…

Nexpose 6.6.271 发布下载,新增功能概览

Nexpose 6.6.271 for Linux & Windows - 漏洞扫描 Rapid7 Vulnerability Management, release Sep 26, 2024 请访问原文链接&#xff1a;https://sysin.org/blog/nexpose-6/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.or…

安全工具 | 搭建带有 Web 仪表板的Interact.sh

介绍 Interactsh 是一个用于检测带外交互的开源工具。它是一种旨在检测导致外部交互的漏洞的工具。本文将主要介绍在子域上设置私有 Interact.sh 服务器以及部署其 Web 应用程序。只需一个 AWS EC2 或 VPS 实例和一个域。 要求 •具有静态IP的AWS EC2 / VPS •拥有自己的域…