事件传播机制 与 责任链模式
1、基本概念
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,将请求沿着处理链传递,直到有一个对象能够处理为止。
2、实现的模块有:
Handler(处理者):定义一个处理请求的接口。
ConcreteHandler(具体处理者):实现了处理者接口,判断自己是否能够处理请求,如果不能将请求传递给下一个处理者。
Request(请求):封装了请求的信息,通常作为处理者方法的参数传递。
3、使用场景
当需要将请求的发送者和接收者进行解耦时。
当有多个对象可以处理同一请求,但不确定哪个对象应该处理时。
当需要动态指定处理请求的顺序时。
4、责任链模式的C++实现:
#include <iostream>
#include <memory>
#include <string> // 抽象处理器类
class Handler {
public: virtual ~Handler() {} // 处理请求的方法 virtual void HandleRequest(const std::string& request) { if (successor_) { successor_->HandleRequest(request); } } // 设置后继处理器 void setSuccessor(std::shared_ptr<Handler> successor) { successor_ = successor; } protected: std::shared_ptr<Handler> successor_;
}; // 具体处理器类A
class ConcreteHandlerA : public Handler {
public: void HandleRequest(const std::string& request) override { if (request == "A") { std::cout << "ConcreteHandlerA handles the request: " << request << std::endl; } else { Handler::HandleRequest(request); } }
}; // 具体处理器类B
class ConcreteHandlerB : public Handler {
public: void HandleRequest(const std::string& request) override { if (request == "B") { std::cout << "ConcreteHandlerB handles the request: " << request << std::endl; } else { Handler::HandleRequest(request); } }
}; // 具体处理器类C
class ConcreteHandlerC : public Handler {
public: void HandleRequest(const std::string& request) override { if (request == "C") { std::cout << "ConcreteHandlerC handles the request: " << request << std::endl; } else { Handler::HandleRequest(request); } }
}; int main() { std::shared_ptr<Handler> handlerA = std::make_shared<ConcreteHandlerA>(); std::shared_ptr<Handler> handlerB = std::make_shared<ConcreteHandlerB>(); std::shared_ptr<Handler> handlerC = std::make_shared<ConcreteHandlerC>(); // 设置责任链 handlerA->setSuccessor(handlerB); handlerB->setSuccessor(handlerC); // 发送请求 handlerA->HandleRequest("A"); handlerA->HandleRequest("B"); handlerA->HandleRequest("C"); handlerA->HandleRequest("D"); return 0;
}
在上述示例中,Handler是抽象处理器类,定义了处理请求的方法。ConcreteHandlerA、ConcreteHandlerB和ConcreteHandlerC是具体处理器类,分别处理请求A、B和C。在创建这些处理器对象时,按照责任链的顺序将它们连接起来。在main函数中,程序创建了一个责任链,将请求依次发送给处理器A、B、C,如果没有任何处理器能够处理请求,则请求不会被处理。
总之,责任链模式是一种非常有用的设计模式,它可以将请求和处理请求的对象解耦,从而提高系统的灵活性和可扩展性。在实际应用中,它可以帮助我们解决很多复杂的问题,提高系统的处理能力和吞吐量,同时也提高了代码的可维护性和可读性。
5、Qt事件传播机制
QT源码:事件系统
QT的事件处理系统同样用到了事件处理系统,其中事件通过事件队列发送到对应的对象,每个对象都可以处理该事件,如果该对象无法处理,将会发给下一个对象。
以下是 QAppliaction 发送鼠标事件给 QWidget 的部分源码:
//接收鼠标事件的对象w
QWidget* w = static_cast<QWidget *>(receiver);
//鼠标事件e
QMouseEvent* mouse = static_cast<QMouseEvent*>(e);......while (w) {//创建一个新的鼠标事件对象,用于在对象树中传播鼠标事件QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());......//如果鼠标事件被接受,打破循环eventAccepted = (w == receiver ? mouse : &me)->isAccepted();if (res && eventAccepted)break;......//如果鼠标事件未被接受,将w设置为w的父组件,继续循环w = w->parentWidget();
}
可以看出, QApplication 将鼠标事件沿着对象树传递,直到有一个对象能够处理为止,符合责任链模式的思想,其中:
QObject:Handler(处理者),定义一个处理鼠标事件的接口。
QWidgt:ConcreteHandler(具体处理者),实现了 QObject 的接口,判断自己是否能够处理鼠标事件,如果不能将请求传递给父类 QWidget。
QMouseEvent:Request(请求),封装了鼠标事件的信息。
QAppliaction:客户端,是请求的发起者。
以上即可展现责任链模式在QT中应用。如果在意细节,可以看下方第6条,否则,后面不用看!
6、Qt事件传播机制 具体细节
事件传播机制和对象树机制共同构成了Qt中对象的一种管理方式和事件的一种传播方式。通过在对象之间建立处理请求的责任链,可以使请求的处理与请求的发起者解耦,提高代码的可扩展性和可维护性。另外,Qt还提供了QObject::installEventFilter
方法,即可以安装一个事件过滤器来处理事件。事件过滤器是一个单独的对象,它可以拦截并处理一个或多个对象的事件。因此,事件过滤器也可以看作责任链模式中的一环。
下面给出Qt源码中如何实现事件传播机制,并且体现出责任链模式的一个示例。注意,这个示例省略了比较多的细节,但作为示例去描述Qt源码中如何体现责任链模式,应该是勉强足够的。
#include <iostream>enum EventType { UnknownEvent, MouseButtonPressEvent };class QEvent {
public:explicit QEvent(EventType type) : _type(type), _accepted(false) {}virtual ~QEvent() {}EventType type() const { return _type; }void accept() { _accepted = true; }void ignore() { _accepted = false; }bool isAccepted() const { return _accepted; }private:EventType _type;bool _accepted;
};class QObject {
public:virtual ~QObject() {}virtual bool event(QEvent *event) {// 默认实现,不处理任何事件return false;}virtual bool eventFilter(QObject *, QEvent *) {// 默认实现,不处理任何事件return false;}
};class QWidget : public QObject {
public:virtual ~QWidget() {}bool event(QEvent *event) override {switch (event->type()) {case MouseButtonPressEvent:mousePressEvent(event);return true;default:return QObject::event(event);}}virtual void mousePressEvent(QEvent *event) {std::cout << "QWidget: Mouse button press event\n";event->accept();}
};
通过上面的示例,可以看到,QObject
,QWidget
和QEvent
三个类的设计和实现,体现了责任链模式。
QWidget
,继承自QObject
,重写了event()
方法,专门处理用户界面事件。例如,当按键事件发生,我们可以获取按下的键码,然后调用事件的accept()
方法表示处理完成,从而阻止事件继续向上传递。如果QWidget
无法处理事件,它会将事件传递给父对象。
QEvent
是所有事件的基类,每个事件有独特的类型标识符。QEvent
类还提供了isAccepted()
、accept()
和ignore()
方法,标记事件是否被接受和处理。一旦事件被处理,我们可以通过调用accept()
方法停止事件的传递,避免重复处理。
作为所有Qt对象的基类,QObject
通过提供event()
和eventFilter()
两个虚函数,构建了事件处理的基础。其中event()
负责处理自身接收到的事件,eventFilter()
则处理需要过滤的事件。如果事件未被处理,它会被传递给父对象,形成责任链。那么传递给父对象的逻辑,在哪里呢?往QWidget::event()
方法里打断点调试就会发现,调用栈会经过QApplication::notify(QObject *receiver, QEvent *e)
,也就是说,事件的分发回经过里面QApplication::notify
。切换到这个方法的调用点查看源代码,可以看到这么一段逻辑:
bool QApplication::notify(QObject* receiver, QEvent* e)
{//其他逻辑//...bool res = false;switch (e->type()) {//处理其他事件类型//...case QEvent::MouseButtonPress:case QEvent::MouseButtonRelease:case QEvent::MouseButtonDblClick:case QEvent::MouseMove:{QWidget* w = static_cast<QWidget*>(receiver);QMouseEvent* mouse = static_cast<QMouseEvent*>(e);QPoint relpos = mouse->pos();if (e->spontaneous()) {if (e->type() != QEvent::MouseMove)QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);// ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms// like OS X (probably others too), can optimize their views by not// dispatching mouse move events. We have attributes to control hover,// and mouse tracking, but as long as we are deciding to implement this// feature without choice of opting-in or out, you ALWAYS have to have// tracking enabled. Therefore, the other properties give a false sense of// performance enhancement.if (e->type() == QEvent::MouseMove && mouse->buttons() == 0&& w->rect().contains(relpos)) { // Outside due to mouse grab?d->toolTipWidget = w;d->toolTipPos = relpos;d->toolTipGlobalPos = mouse->globalPos();QStyle* s = d->toolTipWidget->style();int wakeDelay = s->styleHint(QStyle::SH_ToolTip_WakeUpDelay, 0, d->toolTipWidget, 0);d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive() ? 20 : wakeDelay, this);}}bool eventAccepted = mouse->isAccepted();QPointer<QWidget> pw = w;while (w) {QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());me.spont = mouse->spontaneous();me.setTimestamp(mouse->timestamp());QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags());// throw away any mouse-tracking-only mouse eventsif (!w->hasMouseTracking()&& mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {// but still send them through all application event filters (normally done by notify_helper)d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);res = true;}else {w->setAttribute(Qt::WA_NoMouseReplay, false);res = d->notify_helper(w, w == receiver ? mouse : &me);e->spont = false;}eventAccepted = (w == receiver ? mouse : &me)->isAccepted();if (res && eventAccepted)break;if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))break;relpos += w->pos();w = w->parentWidget();}mouse->setAccepted(eventAccepted);if (e->type() == QEvent::MouseMove) {if (!pw)break;w = static_cast<QWidget*>(receiver);relpos = mouse->pos();QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos);while (w) {if (w->testAttribute(Qt::WA_Hover) &&(!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff, mouse->modifiers());d->notify_helper(w, &he);}if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))break;relpos += w->pos();w = w->parentWidget();}}d->hoverGlobalPos = mouse->globalPos();}break;//处理其他事件类型//...}return res;
}
我们在这里只关心鼠标事件(QEvent::MouseButtonPress
,QEvent::MouseButtonRelease
,QEvent::MouseButtonDblClick
,QEvent::MouseMove:
)的处理。下面分析一下关键的程序段:
1. 在处理鼠标事件时,首先获取当前QWidget
对象w
。
QWidget* w = static_cast<QWidget *>(receiver);
2. 把事件循环遍历至最高级父窗口或直到一个处理了事件的窗口。在此过程中,对于没有成功处理鼠标事件的窗口,事件会沿着窗口的父链继续传递。
while (w) {// 将事件发送给QWidget对象w,尝试让其处理// ...// 当事件已经被接收并得到处理,跳出循环if (res && eventAccepted)break;// 当到达顶层窗口或当前窗口标记为Qt::WA_NoMousePropagation (无鼠标事件传递)时,跳出循环if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))break;// 获取父窗口,在while循环下一轮尝试让父窗口去处理w = w->parentWidget();
}
在这个while循环中,就会不断地去获取父对象,尝试让其处理。事件得到处理,或者当到达顶层窗口,或者当前窗口标记为Qt::WA_NoMousePropagation
(无鼠标事件传递)时,跳出循环。这里就体现出了事件处理的传递链。
可以继续解析上面的程序示例中,"将事件发送给QWidget对
象w,尝试让其处理"部分没有展示出的代码:
1. 根据收到的原始鼠标事件(mouse
)创建一个新的鼠标事件(me
),并使用正确的相对位置(relpos
)更新它。同时设置一些其他属性,如是否自发、时间戳和鼠标事件标志。
QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());
me.spont = mouse->spontaneous();
me.setTimestamp(mouse->timestamp());
QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags());
2. 对于没有鼠标跟踪并且是无按钮按下的鼠标移动事件(仅用于鼠标跟踪的事件),忽略这个事件,并将其传递给所有应用程序事件过滤器。设置结果变量res = true
表示事件已被处理。
if (!w->hasMouseTracking()&& mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {// but still send them through all application event filters (normally done by notify_helper)d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);res = true;
}
3. 否则,尝试将mouse
或me
事件传递给QWidget
对象(视情况而定)。更新事件的自发属性为false
。
else {w->setAttribute(Qt::WA_NoMouseReplay, false);res = d->notify_helper(w, w == receiver ? mouse : &me);e->spont = false;
}
4. 检查事件是否已被接受。这个步骤会影响后续窗口的事件传递。
eventAccepted = (w == receiver ? mouse : &me)->isAccepted();
综上,QObject
作为事件处理接口,QWidget
实现具体的处理逻辑,而QEvent
则扮演了请求的角色,QApplication
参与了事件的分发和向上传递。这几个类的协作为Qt提供了一种高效、灵活且可扩展的事件处理机制,帮助开发者轻松处理各种事件和场景。
总结
至此,我们已经解析了Qt的对象树机制,构建在对象树机制之上的事件传递机制,以及它们背后的设计思想。在后续的文章中,我们可能还会继续解析Qt源码中事件机制相关的设计模式。事件机制确实是Qt中的核心机制之一,我们能够深挖的东西,恐怕还有很多。
原文链接:https://blog.csdn.net/buhuiCyvyan/article/details/138793057
原文链接:https://zhuanlan.zhihu.com/p/631330647
相关文章:
事件传播机制 与 责任链模式
1、基本概念 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,将请求沿着处理链传递,直到有一个对象能够处理为止。 2、实现的模块有: Handler(处理者):定义一个…...
uniapp 展示地图,并获取当前位置信息(精确位置)
使用uniapp 提供的map标签 <map :keymapIndex class"container" :latitude"latitude" :longitude"longitude" ></map> 页面初始化的时候,获取当前的位置信息 created() {let that thisuni.getLocation({type: gcj02…...
Autosar实践——诊断配置(DaVinci Configuration)
文章目录 一、制作诊断数据库文件(cdd文件)二、导入诊断数据库文件并修复模块生成的问题三、创建SWC CS接口Service Ports四、创建Service Runnable五、关联SWC和DCM/DEM模块六、RTE代码编写22服务2E服务31服务DTC Set/Get关联文章列表: Autosar-软件架构 Autosar诊断-简介和…...
植物大战僵尸杂交版全新版v2.1解决全屏问题
文章目录 🚋一、植物大战僵尸杂交版❤️1. 游戏介绍💥2. 如何下载《植物大战僵尸杂交版》 🚀二、解决最新2.1版的全屏问题🌈三、画质增强以及减少闪退 🚋一、植物大战僵尸杂交版 《植物大战僵尸杂交版》是一款在原版《…...
【code-server】Code-Server 安装部署
Code-Server 安装部署 1.环境准备 可以参考 https://coder.com/docs/code-server/install code-server的安装流程进行安装,主机环境是 Centos7 建议使用 docker 方式进行安装,可能会出现如下报错,需要升级 GNC 的版本,由于影响较…...
博客摘录「 YOLOv5模型剪枝压缩」2024年5月11日
添加L1正则来约束BN层系数 语义边缘检测和语义分割的关系调研结果为,语义信息可以用来增强语义分割的效果,也有一定的优点和采用理由,但此类论文的数量并不是很多,语义分割的多数方法还是使用深度学习直接做像素分类。在对比两者…...
HttpSecurity
这是Spring Security提供的配置类, 用户保护基于HTTP的请求 ,通过HttpSecurity可以设置各种安全设置{认证,授权,CSRF保护,会话管理,异常处理} 主要功能和配置: 1.认证配置: 配置登录和登出功能,指定登录页面、登录处理 URL、成功和失败处理器等。配置认证方式,如表单登录、…...
Mysql union语句
开源项目SDK:https://github.com/mingyang66/spring-parent 个人文档:https://mingyang66.github.io/raccoon-docs/#/ mysql union操作符用于连接两个以上的select语句的结果组合到一个结果集,并去除重复的行,每个select语句的雷叔…...
MySQL之高级特性(四)
高级特性 查询缓存 什么情况下查询缓存能发挥作用 并不是什么情况下查询缓存都会提高系统性能的。缓存和失效都会带来额外的消耗,所以只有当缓存带来的资源节约大于本身的资源消耗时才会给系统带来性能提升。这跟具体的服务器压力模型有关。理论上,可…...
roles安装wordpress
debug模块 1.如何查看ansible-playbook执行过程中产生的具体信息 vim test3.yaml --- - hosts: allremote_user: roottasks:- name: lsshell: ls /rootregister: var_stdout # register:将var_stdout注册为变量- name: debugdebug:var: var_stdout # 查看所有的输出信息#var…...
【Python高级编程】饼状图中autopct和startangle用来做什么的
autopct 设置饼状图中每个扇区的百分比标签。接受一个格式字符串,用于指定如何格式化标签。默认值为 %.1f%%,表示保留一位小数的百分比格式。可以设置为 None 以禁用百分比标签。 startangle 设置饼状图中第一个扇区的起始角度。角度以顺时针方向从 3…...
【ARM Coresight Debug 系列 -- ARMv8/v9 Watchpoint 软件实现地址监控详细介绍】
请阅读【嵌入式开发学习必备专栏 】 文章目录 ARMv8/v9 Watchpoint exceptionsWatchpoint 配置信息读取Execution conditionsWatchpoint data address comparisonsSize of the data accessWatchpoint 软件配置流程Watchpoint Type 使用介绍WT, Bit [20]: Watchpoint TypeLBN, B…...
jvm工具-jps、jstat、jmap、jstack
一、jps jps -v 【输出进程启动参数】 [rootVM-8-2-centos ~]# jps -v 12401 Jps -Dapplication.home/usr/local/jdk1.8.0_241 -Xms8m 16964 jar 其他参考 Java八股文必看,入门到深入理解jvm虚拟机之基础故障指令【jps,jstate...】-CSDN博客 二、j…...
LVS负载均衡群集+NAT部署
目录 一、企业群集应用概述 1.1 群集的含义 1.2 企业群集分类 二、负载均衡群集架构和工作模式 2.1负载均衡的结构 2.2负载均衡群集工作模式分析 三、LVS虚拟服务器 3.1Linux Virtual Server 3.2LVS必要的工具 3.3LVS的负载调度算法 一、企业群集应用概述 1.1 群集的…...
使用 Oracle SQL Developer 导入数据
使用 Oracle SQL Developer 导入数据 1. 导入过程 1. 导入过程 选择要导入数据的表, 然后单击右键,选择"导入数据", 浏览本地文件,选择正确的工作表, 按默认, 按默认, 根据情况修改&…...
品质主管的面试题目
在品质主管的面试中,面试官可能会提出一系列问题来评估应聘者的经验、技能和专业知识。以下是一些常见的品质主管面试题,你可以提前准备,以更好地展示自己的能力和适应性。 一、自我介绍与背景了解 请简单介绍一下自己,包括教育背景、工作经验等。你在过去的工作经历中,主…...
算法专题总结链接地址
刷力扣的时候会遇到一些总结类型的题解,在此记录,方便自己以后找 前缀和 前缀和https://leetcode.cn/problems/unique-substrings-in-wraparound-string/solutions/432752/xi-fa-dai-ni-xue-suan-fa-yi-ci-gao-ding-qian-zhui-/ 单调栈 单调栈https:…...
Oracle--存储结构
总览 一、逻辑存储结构 二、物理存储结构 1.数据文件 2.控制文件 3.日志文件 4.服务器参数文件 5.密码文件 总览 一、逻辑存储结构 数据块是Oracle逻辑存储结构中的最小的逻辑单位,一个数据库块对应一个或者多个物理块,大小由参数DB_BLOCK_SIZE决…...
【计算机毕业设计】259基于微信小程序的医院综合服务平台
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
HP惠普暗影精灵10 OMEN Gaming Laptop 16-wf1xxx原厂Win11系统镜像下载
惠普hp暗影精灵10笔记本电脑16-wf1000TX原装出厂Windows11,恢复开箱状态oem预装系统安装包,带恢复重置还原 适用型号:16-wf1xxx 16-wf1000TX,16-wf1023TX,16-wf1024TX,16-wf1025TX, 16-wf1026TX,16-wf1027TX,16-wf1028TX,16-wf1029TX, 16-wf1030TX,16-…...
[Day 9] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
區塊鏈的主要應用場景 區塊鏈技術自2008年首次由中本聰提出以來,已經迅速發展並應用於各個領域。它的去中心化、透明和不可篡改等特性使其在金融、供應鏈、醫療健康、物聯網、數字身份等多個方面展現出巨大的潛力。本文將深入探討區塊鏈的主要應用場景,…...
van-list 遇到的问题
将公司项目H5页面重构的时候,有一个类似购物车的页面,需要上拉加载,下拉刷新。使用的UI组件的是vant,其中看起来van-list 很符合基本需求,就果断进行了copy 修改。但是,在进行具体的业务交互的时候突然发现…...
DockerCompose+Jenkins+Pipeline流水线打包Vue项目(解压安装配置Node)入门
场景 DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门: DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门-CSDN博客 以上使用流水线配置和打包springboot后台项目,如果要使…...
【新课程】PICO VR 交互开发指南
从PICO开始,迈向XR跨平台开发 Unity XR Interaction Toolkit (简称XRI)是一套跨平台的 XR 交互开发工具包,随着版本的更新与完善,逐渐获得了开发者的青睐。各 XR 平台逐步推荐开发者采用 XRI 作为首选的交互开发工具为…...
天童美语:为了得体退出的那一天,你一定要好好爱孩子
父母最大的成就就是孩子可以独立,自己完成自己的人生。为了得体退出的那一天,你一定要好好爱你的小孩,因为每一天都在过去。当我们站在孩子成长的十字路口,面对那个终将到来的退出时刻,心中总会涌起一股难以言表的情感…...
什么是JWT?为什么用JWT?JWT的实战案例
JWT学习资料 1.什么是JWT?【头部(Header)、载荷(Payload)和签名(Signature)】2.为什么要用JWT?3.JWT 使用全局变量JWT 创建JWT的应用(token放在返回信息中)JWT验证 4.JWT 原理 1.什么是JWT?【头部(Header)、载荷(Payload)和签名(Signature)】 JWT(JS…...
SpringBoot+Vue小区物业管理系统 附带详细运行指导视频
文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1.用户登录代码2.查询小区信息代码3.保存缴费信息代码 一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBootVue框架开发的小区物业管理系统。首先…...
在不使用js在情况下只用css实现瀑布流效果
使用到的是grid 布局,需要注意的是grid-template-rows: masonry; 目前只有Firefox 浏览器支持这个效果,而且还是一个实验性属性需要在设置里面开发实验性选项才行。 实例 <!DOCTYPE html> <html> <head><title>Document</ti…...
AMS(ActivityManagerService)源码解析2,Android应用是如何被启动的
一个Android应用是如何被启动的 前言总结1. 启动Application1.1 拉起一个新的进程1.2 启动Application1.3 AMS阶段1.4 创建Instrumentation和Application 2. 启动Activity2.1 回到AMS,启动第一个Activity 参考资料 前言 基于源码API 28,30以后的版本启动…...
数据库事务隔离级别
前几天项目上合作公司的系统出现了一次死锁,突然想到由于近几年开发设计的系统并发用户比较少,很久没有碰到过死锁了,因此对死锁的概念也比较生疏了,需要温习一下。 事务 先从最基本的概念开始,事务、及其ACID特性。…...
wordpress bbs插件/游戏合作渠道
文丨安迪斯晨风有一些生僻字,一眼看上去觉得和常用字没区别,不过等你揉揉眼睛仔细看就会发现它们像是“缺胳膊少腿儿”一样。作为一个强迫症患者,宝宝总想拿起笔给它添上一丢丢。下面就让我们来认识一下这些字吧!首先出场的是“戓…...
在哪些网站可以做企业名称预审/上海最新事件
氚云tERP 一、概述 氚云tERP是一套针对商贸类企业研制的一套信息化解决方案。产品覆盖从销售、库存、采购、财务、人事、流程管理一体化管理。帮助企业搭建一个简洁、高效的运营管理平台,实现人、财、物、供、销全面的管理。 二、优势 集成钉钉:全面集成…...
网站如何兼容大多浏览器/国际新闻大事
环境:win10,64位 进入下载:微软官网downlord 注意:64位系统要同时安装x86和x64才可以,arm无需下载...
数字尾巴+wordpress/互联网培训机构排名前十
查找题目描述:输入数组长度 n输入数组 a[1...n]输入查找个数m输入查找数字b[1...m]输出 YES or NO 查找有则YES 否则NO 。输入:输入有多组数据。每组输入n,然后输入n个整数,再输入m,然后再输入m个整数(1<m<n<…...
泉州网站设计/搜索引擎营销特点是什么
目录 0. 相关文章链接 1. Elasticsearch简介 2. 应用场景 3. 工程化案例 4. 用户画像标签数据存储总结 注:此博文为根据 赵宏田 老师的 用户画像方法论与工程化解决方案 一书读后笔记而来,仅供学习使用 0. 相关文章链接 用户画像文章汇总 1. Ela…...
怎么找网站的后台地址/网络推广如何收费
年年岁岁花相似,岁岁年年各不同,当气温渐暖时,又即将迎来新一届毕业生大军进入社会,而这新的大军里的面孔已焕然一新,也许你就是其中的一员。 初出校园,毕竟学校不同于社会,学习不同于工作。每个…...