Android audio(2)-audioservice
AudioService是Android的系统服务(systemservice),由SystemServer负责启动。提供Android APK 所需的非数据通路(playback/capture)相关的audio 功能实现,是binder通信中的server端,与之对应的 Client 端是应用进程中的AudioManager。两者之间通过binder进行通信。注意audioService没有自己独立的进程,这点和后面涉及的audioserver有所不同。
我们要注意Android系统本身不是个系统,没有内存管理,进程管理,设备管理等系统功能。android可以理解为linux内核+定制服务。
一、audioservice服务启动流程
1、SystemServer
源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java
boolean isArc = context.getPackageManager().hasSystemFeature("org.chromium.arc");private void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("StartAudioService");if (!isArc) {0mSystemServiceManager.startService(AudioService.Lifecycle.class);//启动audioservice服务} else {String className = context.getResources().getString(R.string.config_deviceSpecificAudioService);try {mSystemServiceManager.startService(className + "$Lifecycle");} catch (Throwable e) {reportWtf("starting " + className, e);}}t.traceEnd();
}
SystemServer在startOtherServices中启动了AudioService。
2、AudioService
源码位置:/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub implements AccessibilityManager.TouchExplorationStateChangeListener, AccessibilityManager.AccessibilityServicesStateChangeListener {public static final class Lifecycle extends SystemService {//父类就是我们所说的系统服务private AudioService mService;public Lifecycle(Context context) {super(context);mService = new AudioService(context);//创建audioservice实例}@Overridepublic void onStart() {publishBinderService(Context.AUDIO_SERVICE, mService);//向系统注册audioservice服务}@Overridepublic void onBootPhase(int phase) {if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {mService.systemReady();}}}
}
从上面代码可以看出,SystemServer实际启动的是 AudioService 中的 Lifecycle 类,该类继承自SystemService,在构造函数中创建 AudioService实例。为什么audioflinger和audiopolicyservice直接继承自binderservice而不是定义一个内部类继承?这个问题我还没想明白。
二、AudioService功能概述
AudioService 继承自 IAudioService.Stub。IAudioService.Stub 类是通过 IAudioService.aidl 生成。AudioService 位于 Binder Native 端。AudioManager 持有 AudioService 的 Binder Proxy 端,是 AudioService 在客户端的一个代理。几乎所有客户端对 AudioManager 进行的请求,最终都会交由 AudioService 实现。
AudioService 是整个音频系统在java层面的关键类,它的功能非常多,各功能在audioservice内部也通过类进行了封装,功能内部具有较高的内聚性,下面介绍 AudioService 的主要功能。观察audioservice代码的演变历史,可以看出google对代码还是有持续的重构动作。这点很值得我们学习。
1、音量调节
在 Android 手机上有两种改变系统音量的方式。一,通过手机的音量键进行音量调整,二,从设置界面中调整某一种类型音频的音量。在AndroidTV中还支持用红外/蓝牙遥控器调节音量。另外,应用程序可以随时将某种类型的音频静音。这些功能都是通过 AudioService 实现。
// 注意这里的suggest,表示调用者期望调整的音量类型
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller, int uid, boolean hasModifyAudioSettings, int keyEventMode)
2、音频设备管理
AudioService 除了提供音量设置功能外,还接收音频设备的插拔通知,并通过JNI层通知到native服务,以检测耳机的插入过程为例。
有线设备管理器
在 SystemServer 的 startOtherServices 方法中启动了有线设备的监听服务WiredAccessoryManager。
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("StartWiredAccessoryManager");try {// 监听有线耳机的变化inputManager.setWiredAccessoryCallbacks(new WiredAccessoryManager(context, inputManager));} catch (Throwable e) {reportWtf("starting WiredAccessoryManager", e);}t.traceEnd();
}
WiredAccessoryManager 中通过 WiredAccessoryObserver 来监听有线设备的插拔。
源码位置:/frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java
private final WiredAccessoryObserver mObserver;public WiredAccessoryManager(Context context, InputManagerService inputManager) {......mObserver = new WiredAccessoryObserver();
}class WiredAccessoryObserver extends UEventObserver {private final List<UEventInfo> mUEventInfo;......private List<UEventInfo> makeObservedUEventList() {if (!mUseDevInputEventForAudioJack) {uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT);if (uei.checkSwitchExists()) {retVal.add(uei);} else {......}}uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL, 0);if (uei.checkSwitchExists()) {retVal.add(uei);} else {......}uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0, 0);if (uei.checkSwitchExists()) {retVal.add(uei);} else {uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0, 0);if (uei.checkSwitchExists()) {retVal.add(uei);} else {......}}return retVal;}@Overridepublic void onUEvent(UEventObserver.UEvent event) {if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());try {String devPath = event.get("DEVPATH");String name = event.get("SWITCH_NAME");int state = Integer.parseInt(event.get("SWITCH_STATE"));synchronized (mLock) {updateStateLocked(devPath, name, state);}} catch (NumberFormatException e) {......}}private void updateStateLocked(String devPath, String name, int state) {for (int i = 0; i < mUEventInfo.size(); ++i) {UEventInfo uei = mUEventInfo.get(i);if (devPath.equals(uei.getDevPath())) {updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));return;}}}
private void updateLocked(String newName, int newState) {Log.i(TAG, "MSG_NEW_DEVICE_STATE");Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,mHeadsetState, "");mHandler.sendMessage(msg);//这个消息的处理就会调用AudioService的setWiredDeviceConnectionStatemHeadsetState = headsetState;
}......
}
上面 WiredAccessoryObserver 会通过监听 /devices/virtual/switch/ 的节点变化,并根据变化调用AudioService的setWiredDeviceConnectionState通知 AudioService进行耳机插播事件的处理。
3、音频焦点管理
常见的音频焦点管理功能有如下两种。
1:手机正在播放音乐,突然电话来电,这时候音乐播放声音会停止,而只留电话声音。
2:手机正在播放音乐,这时候如果导航应用播报,音乐播放音量会减小,等待导航播报结束后,音乐播放音量会恢复。
上面两个场景便用到了android的音频焦点管理,音频焦点策略就是拿到焦点的应用才能播放声音,每个音频实例播放之前都应该向 AudioService 申请焦点,申请成功才开始播放;当一个音频实例正在播放的过程中,此时焦点被其他音频播放实例抢占,这时候正在播放的的音频实例会丢失焦点,失去焦点的音频播放实例应该根据实际情况来进行静音,暂停播放或者适当减小音量等操作,等被抢占的焦点被归还的时候再把之前的音频播放状态恢复。
音频焦点策略只是android提供的一个机制,并且建议APK开发者遵守,如果应用都没有采用音频焦点策略管理机制,那么所有应用一起混合播放出来的音频声音,最终输出的声音内容将不可预料。通话相关的音频模块也会申请音频焦点,音频焦点的优先级是最高的,可以从任何拥有音频焦点的音频播放实例中抢走音频焦点。
关键流程/步骤:
1.申请焦点
2.失去焦点
3.恢复焦点
总结:
1.AM/AS是个C/S架构。AS的承载进程是systemserver。(进程名system_server)
2.AS三大功能:音量,设备,焦点。
3.焦点三大核心:申请,失去,恢复。(记忆口诀:生石灰)申失恢
启发:
焦点可以看做一类资源,仔细思考焦点的三大核心,我们不难发现和进程的CPU调度有相似之处。
进程要想运行就必须获得CPU的调度,类似焦点的申请,当更高优先级的进程出现或者时间片用完进程就会失去CPU调度。
类似失去焦点。重新进入等待队列。当进程在等待队列中重新获得调度后,又可以执行了,这就类似恢复焦点。
相关文章:
Android audio(2)-audioservice
AudioService是Android的系统服务(systemservice),由SystemServer负责启动。提供Android APK 所需的非数据通路(playback/capture)相关的audio 功能实现,是binder通信中的server端,与之对应的 C…...
星城幻境:科技与千年文脉的交响诗-长沙
故事背景 故事发生在中国湖南长沙,通过六个充满未来感的城市景观,展现人工智能修复古建筑、生态摩天楼、全息水幕许愿等场景,描绘科技赋能下历史文脉与未来城市的共生图景。 故事内容 从岳麓书院清晨的智能修复到湘江夜空的数字烟花ÿ…...
记录学习的第二十三天
老样子,每日一题开胃。 我一开始还想着暴力解一下试试呢,结果不太行😂 接着两道动态规划。 这道题我本来是想用最长递增子序列来做的,不过实在是太麻烦了,实在做不下去了。 然后看了题解,发现可以倒着数。 …...
sql-labs靶场 less-1
文章目录 sqli-labs靶场less 1 联合注入 sqli-labs靶场 每道题都从以下模板讲解,并且每个步骤都有图片,清晰明了,便于复盘。 sql注入的基本步骤 注入点注入类型 字符型:判断闭合方式 (‘、"、’、“”…...
AI-人工智能-基于LC-MS/MS分子网络深度分析的天然产物成分解析的新策略
Anal Chem∣张卫东教授团队开发基于LC-MS/MS分子网络深度分析的天然产物成分解析的新策略 2024年9月23日,海军军医大学张卫东教授团队在Analytical Chemistry(IF6.7)上发表了题为“In-Depth Analysis of Molecular Network Based on Liquid …...
IntelliJ IDEA使用技巧(json字符串格式化)
文章目录 一、IDEA自动格式化json字符串二、配置/查找格式化快捷键 本文主要讲述idea中怎么将json字符串转换为JSON格式的内容并且有层级结构。 效果: 转换前: 转换后: 一、IDEA自动格式化json字符串 步骤一:首先创建一个临…...
【Java设计模式】第8章 单列模式讲解
8-1 单例模式讲解 定义与类型 定义:保证一个类仅有一个实例,并提供一个全局访问点。类型:创建型模式。适用场景 需要确保任何情况下绝对只有一个实例。实际应用: 网站计数器(单服务)。应用配置、线程池、数据库连接池。优点 减少内存开销(仅一个实例)。避免资源多重占…...
【Java设计模式】第4章 简单工厂讲解
4. 简单工厂模式 4.1 简单工厂讲解 定义:由一个工厂对象决定创建哪种产品类的实例,属于创建型模式,但不属于GoF 23种设计模式。适用场景: 工厂类负责创建的对象较少。客户端仅需传入参数,无需关心对象创建逻辑。优点: 客户端只需传入参数即可获取对象,无需知道创建细节…...
Spring Boot 常用依赖介绍
依赖总括 1. 核心依赖:Spring Web、Spring Data JPA、MySQL Driver。 2. 开发工具:Lombok、Spring Boot DevTools。 3. 安全与权限:Spring Security。 4. 测试与文档:Spring Boot Starter Test、Swagger。 5. 性能优化&#…...
判断矩阵A是否可以相似对角化
【例题1】 【例题2】...
第三方软件测试公司进行安全性测试有哪些好处?
在信息技术飞速发展的今天,软件已成为各行业运作的核心组成部分。然而,伴随而来的软件安全问题也愈发显著,因此软件产品安全性测试不容忽视。随着软件市场的激烈竞争,企业为了更好的专心产品开发,会将安全性测试服务交…...
下一代楼宇自控的中枢神经:ARM终端的生态
某跨国半导体工厂的洁净车间突然触发气体泄漏报警。此时,ARM应急广播终端在200毫秒内完成全楼宇语音播报,同步联动门禁系统解锁逃生通道,指挥中心大屏自动弹出事故区域监控画面——这套价值27万元的预警系统,在投产首年就避免了可…...
R语言进行判别分析
Fisher判别法、距离判别法、Bayes判别法基本理论、方法: Fisher判别法 理论基础: Fisher判别法旨在通过选择合适的投影方向,最大化不同类别之间的类间差异性,同时最小化类内差异性。这种投影方向使得在低维空间中样本点的类别可…...
Nacos 服务发现的流程是怎样的?客户端如何获取最新的服务实例列表?
服务发现是微服务架构的核心组件,它允许一个服务(消费者)动态地找到它需要调用的另一个服务(提供者)的网络地址(IP 和端口),而无需硬编码这些地址。 整体流程概览: 服务提供者 (Pr…...
Java全栈项目--校园快递管理与配送系统(5)
源代码续 <template><div class"app-container"><el-card class"box-card"><div slot"header" class"clearfix"><span>通知统计</span><div class"header-operations"><el-d…...
UE5 本地化
文章目录 打开本地化面板设置本地化翻译设置文本收集路径添加语言收集需要翻译的文本手动翻译导入导出编译 使用本地化启动代码修改语言 打开本地化面板 UE4: UE5: 设置本地化翻译 设置文本收集路径 UE5可以自动帮我们收集需要显示的文本ÿ…...
用c语言写一个linux进程之间通信(聊天)的简单程序
使用talk 用户在同一台机器上talk指令格式如下: talk 用户名ip地址 [用户终端号] 如果用户只登录了一个终端,那么可以不写用户终端号,如: talk userlocalhost可以使用who指令来查看当前有哪些用户登录,他的终端号…...
同时支持Vue2/Vue3的图片懒加载组件(支持懒加载 v-html 指令梆定的 html 内容)
🚀 vue-lazyload-imgs(LazyLoadImgs) 组件简介 详情见:https://npmjs.com/package/vue-lazyload-imgs 安装方法: npm i vue-lazyload-imgs(不要安装为开发依赖,应为产品依赖) 适用环…...
Qt容器类在元对象系统中使用
解释 “QVector没有被注册到Qt的元对象系统中”这句话的意思是:QVector<double>这种数据类型没有被Qt的元对象系统(Meta-Object System)识别和管理。Qt的元对象系统是Qt框架的核心部分,它提供了信号与槽机制、动态属性系统…...
Qt中的信号与槽及其自定义
信号源:哪个控件发的信号 信号的类型:用户进行不同的操作就会触发不同的信号 如点击按钮,在输入框移动光标,勾选一个复选框,选 择一个下拉框 信号的处理方式:槽(slot)----也就是函数,Qt中用con…...
【已完结STM32】--自学江协科技笔记汇总
以下学习笔记代码均来自b站江协科技视频 笔记汇总完结 文章笔记对应江科大视频新建工程【2-2】新建工程江科大STM32-GPIO输出 点亮LED,LED闪烁,LED流水灯,蜂鸣器(学习笔记)_unit32-t rcc-apb2periph-CSDN博客 【3-1】…...
科技快讯 | 索诺瓦携手清华大学共筑听力无障碍未来;中国探月工程总设计师:未来月球上能打电话;Shopify要求员工证明AI无法取代其工作
索诺瓦携手清华大学共筑听力无障碍未来 2024年末,60岁以上人口超3.1亿,听力损失比例高达11%。清华大学无障碍发展研究院与索诺瓦集团深化合作,共同推动听力无障碍环境建设。2023年9月,《无障碍环境建设法》实施,2024年…...
[实战] 天线阵列波束成形原理详解与仿真实战(完整代码)
天线阵列波束成形原理详解与仿真实战 1. 引言 在无线通信、雷达和声学系统中,波束成形(Beamforming)是一种通过调整天线阵列中各个阵元的信号相位和幅度,将电磁波能量集中在特定方向的技术。其核心目标是通过空间滤波增强目标方…...
北京自在科技:让万物接入苹果Find My网络的″钥匙匠″
在AirTag掀起全球防丢热潮的今天,越来越多的第三方产品开始接入苹果Find My网络——从充电宝到电动车,从行李箱到保温杯,用户只需打开iPhone的「查找」App,就能实时定位这些物品。 北京自在科技有限责任公司早在苹果推出Find My开…...
区块链是怎么存储块怎么找到前一个块
前言:学习区块链的过程中在想怎么管理区块链呢 📌 推荐项目回顾: 👉 Jeiwan 的 blockchain_go 项目 GitHub 地址:https://github.com/Jeiwan/blockchain_go ❓它是怎么存储区块 & 找前一个区块的? 项…...
聚类算法 ap 聚类 谱聚类
AP聚类(Affinity Propagation Clustering)是一种基于消息传递的聚类算法,由Brendan J. Frey和Delbert Dueck于2007年提出。与传统的聚类算法(如K-Means)不同,AP聚类不需要预先指定聚类数量,而是…...
习题与正则表达式
思路: 二分查找: left 1(最小可能距离),right L(最大可能距离)。 每次取 mid (left right) / 2,判断是否可以通过增设 ≤ K 个路标使得所有相邻路标的距离 ≤ mid。 贪心验证…...
数据库管理工具实战:IDEA 与 DBeaver 连接 TDengine(一)
一、引言 在当今数字化时代,数据如同企业的生命线,而数据库则是承载这些宝贵数据的关键基础设施。TDengine 作为一款高性能的时序数据库,在物联网、工业互联网、车联网、IT 运维等众多领域中发挥着举足轻重的作用。它以其卓越的性能、高效的…...
聚类Clustering和分类Classification的区别
目的: 聚类:旨在将数据集中的样本分成若干组(簇),使得同一组内的样本在某种意义上更相似,而不同组的样本差异更大。聚类是一种探索性分析,用于发现数据中的自然结构。分类:旨在根据已…...
对比 redis keys 命令 ,下次面试说用 scan
Redis SCAN 命令使用指南 SCAN 是 Redis 提供的一种非阻塞迭代器命令,用于逐步遍历 Redis 数据库中的键。相比于 KEYS 命令,SCAN 不会一次性加载所有键,因此对性能的影响较小,适合在生产环境中使用。 以下是关于 SCAN 的详细用法…...
【Java设计模式】第6章 抽象工厂模式讲解
6. 抽象工厂模式 6.1 抽象工厂讲解 定义:提供一个接口创建一系列相关或依赖对象,无需指定具体类。核心概念: 产品等级结构:同一类型的不同产品(如Java视频、Python视频)。产品族:同一工厂生产的多个产品(如Java视频 + Java手记)。适用场景: 需要创建多个相关联的产品…...
设计模式 - 代理模式
代理模式 代理模式是一种结构型设计模式,它允许你提供一个代理对象来控制对另一个对象的访问。代理模式可以在不改变原始对象的情况下,增强或控制对原始对象的访问。代理模式通常用于延迟加载、访问控制、日志记录、性能监控等场景。 1.静态代理 静态…...
Unity-Xlua热更和AssetBundle详解
从今天开始我们深入Unity的组件,最近的一系列事让我明白学习技术不能只有广度,如走马观花,虽然你可能确实学到了皮毛,但是没有足够深厚的理解,是无法融入自己的东西的,那么你就只是在用别人的工具而不是自己…...
【企业级数据安全】掌握高性能Log4j2敏感信息脱敏方案
前言 在数据安全合规日益严格的今天,日志中的敏感信息保护已成为企业IT建设的必备环节。本文带您深入了解如何打造一套高性能、可实时配置的Log4j2日志脱敏插件,轻松应对各类敏感数据保护需求,让您的系统既满足合规要求,又不牺牲…...
力扣刷题——606.根据二叉树创建字符串
给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。 空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映…...
图像处理中的 Gaussina Blur 和 SIFT 算法
Gaussina Blur 高斯模糊 高斯模糊的数学定义 高斯模糊是通过 高斯核(Gaussian Kernel) 对图像进行卷积操作实现的. 二维高斯函数定义为 G ( x , y , σ ) 1 2 π σ 2 e − x 2 y 2 2 σ 2 G(x, y, \sigma) \frac{1}{2\pi \sigma^2} e^{-\frac{x^2 y^2}{2\sigma^2}} G(x…...
AWS区块链游戏场景技术解决方案:全球节点与去中心化架构实践
一、区块链游戏的技术挑战与架构需求 区块链游戏作为Web3领域的重要应用场景,其技术架构需要满足以下核心需求: 分布式账本的高效同步与共识验证 智能合约的安全执行环境 全球玩家的低延迟交互体验 动态扩展的节点网络支持 海量NFT资产的可靠存储 …...
AWS VPC深度解析:构建安全可靠的云网络基础设施
1. 引言 在云计算时代,网络基础设施的重要性不言而喻。Amazon Web Services (AWS) 的Virtual Private Cloud (VPC)为用户提供了一个强大而灵活的网络环境,使他们能够在AWS云中构建安全、可扩展的应用程序。本文将全面剖析AWS VPC的核心特性,帮助读者深入理解如何利用VPC构建高…...
青少年编程与数学 02-016 Python数据结构与算法 08课题、图
青少年编程与数学 02-016 Python数据结构与算法 08课题、图 一、图1. 图的基本概念1.1 定义1.2 顶点和边1.3 图的分类1.4 特殊术语 2. 图的表示方法1. 邻接矩阵(Adjacency Matrix)2. 邻接表(Adjacency List)3. 边列表(…...
微信小程序:动态表格实现,表头单元格数据完全从data中获取,宽度自定义,自定义文本框,行勾选,样式效果,横向滚动表格(解决背景色不足的问题)等
一、样式效果 二、代码 1、wxml <view class"line flex flex-center"><view class"none" wx:if"{{info.length 0}}">暂无料号</view><view wx:else class"table-container"><!-- 动态生成表头 -->&…...
MySQL学习笔记集--游标
游标 在MySQL中,游标(Cursor)是一种数据库对象,它允许您逐行处理查询结果集。游标通常与存储过程一起使用,因为它们需要在存储过程或函数中声明和操作。游标的使用涉及几个步骤:声明游标、打开游标、从游标…...
Microsoft Defender Antivirus Service服务占用CPU过高
下载火绒安全,用它替代 Microsoft Defender,并关闭 Microsoft Defender 两步禁用Windows Defender Antivirus Service_microsoft defender antivirus service-CSDN博客 Windows10/11家庭版 关闭方法 按 ‘Win键R’,输入 “regedit”&#…...
Ansible(7)——管理机密与事实
目录 一、管理机密: 1、Ansible Vault : 2、ansible-vault 命令行工具: (1)创建加密文件: (2)查看加密文件: (3)编辑现有加密文件…...
consul服务注册与发现(go)-学习笔记
参考博客 1、服务实例接口与默认实现 type ServiceInstance interface {// 获取服务实例的唯一IDGetInstanceId() string// 获取服务IDGetServiceId() string// 获取服务实例的主机名或IP地址GetHost() string// 获取服务实例的端口号GetPort() int// 判断服务实例是否使用HT…...
golang-defer延迟机制
defer延迟机制 defer是什么 defer是go中一种延迟调用机制。 执行时机 defer后面的函数只有在当前函数执行完毕后才能执行。 执行顺序 将延迟的语句按defer的逆序进行执行,也就是说先被defer的语句最后被执行,最后被defer的语句,最先被执…...
字符串哈希算法详解:原理、实现与应用
字符串哈希是一种高效处理字符串匹配和比较的技术,它通过将字符串映射为一个唯一的数值(哈希值),从而在O(1)时间内完成子串的比较。本文将结合代码实现,详细讲解前缀哈希法的工作原理,并通过流程图逐步解析…...
python-Leetcode 65.搜索旋转排序数组
题目: 整数数组nums按升序排列,数组中的值互不相同 在传递给函数之前,nums在预先未知的某个小标K上进行了旋转,使数组变为[nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]],小标从0开始计数。…...
蓝桥杯 C/C++ 组历届真题合集速刷(二)
一、0ASC - 蓝桥云课 (单位换算)算法代码: #include <iostream> using namespace std; int main() {printf("%d",L);return 0; } 二、0时间显示 - 蓝桥云课 (单位换算)算法代码: #inclu…...
react的redux总结
目录 一、Antd 1.1、基本使用 1.2、自定义主题 二、Redux 2.1、工作流程 2.2、理解react-redux 2.3、优化 2.3.1、简写mapDispatch 2.3.2、Provider组件 2.4、数据共享 2.4.1、编写Person组件 2.4.2、Person组件的reducer 2.4.3、完成数据共享 2.5、求和案例 2.…...
MySQL视图
一、视图的本质与分类 1. 定义 虚拟表:视图不存储数据,本质是保存的查询语句(SELECT),每次访问视图时动态执行查询并返回结果。 逻辑抽象:基于一个或多个基表(或视图)创建…...