Android 10.0 截屏流程
通常未通过特殊定制的 Android 系统,截屏都是经过同时按住音量下键和电源键来截屏。本篇文章就只讨论使用这些特殊按键来进行截屏。
这里我们就要明白事件是在哪里进行分发拦截的。通过源码的分析,我们发现是在PhoneWindowManager.java 中。
PhoneWindowManager#interceptKeyBeforeQueueing()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {if (!mSystemBooted) {// If we have not yet booted, don't let key events do anything.return 0;}// 省略部分代码......// Handle special keys.switch (keyCode) {......case KeyEvent.KEYCODE_VOLUME_DOWN:case KeyEvent.KEYCODE_VOLUME_UP:case KeyEvent.KEYCODE_VOLUME_MUTE: {// 按下音量键调用handleVolumeKey(event, policyFlags);......break;}......case KeyEvent.KEYCODE_POWER: {......if (down) {// 按下电源键将调用interceptPowerKeyDown(event, interactive);} else { interceptPowerKeyUp(event, interactive, canceled);}break;}}return result;}
1、电源键处理
PhoneWindowManager#interceptPowerKeyDown()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {// 省略部分代码......// Latch power key state to detect screenshot chord.if (interactive && !mScreenshotChordPowerKeyTriggered&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {// power键按下的标志mScreenshotChordPowerKeyTriggered = true;// 获取 Power 键的触发时间mScreenshotChordPowerKeyTime = event.getDownTime();// 处理屏幕截图事件interceptScreenshotChord();// 这个方法应该是消耗、拦截事件的,避免改变音量、铃声等。interceptRingerToggleChord();}// 省略部分代码......}
interceptScreenshotChord()该方法下面再说,先介绍电源按键、音量按键的处理。
2、音量键处理
PhoneWindowManager#handleVolumeKey()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void handleVolumeKey(KeyEvent event, int policyFlags) {final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;final int keyCode = event.getKeyCode();final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {if (down) {// Any activity on the vol down button stops the ringer toggle shortcutcancelPendingRingerToggleChordAction();if (interactive && !mScreenshotChordVolumeDownKeyTriggered&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {// Volume键按下的标志mScreenshotChordVolumeDownKeyTriggered = true;// 获取 Volume 键的触发时间mScreenshotChordVolumeDownKeyTime = event.getDownTime();// 赋值 false 该属性为了防止截屏的时候音量下键生效出现调节音量的 dialog 状态值mScreenshotChordVolumeDownKeyConsumed = false;// 防止触发 Power 键长按功能cancelPendingPowerKeyAction();//处理屏幕截图事件interceptScreenshotChord();// 拦截相关快捷键interceptAccessibilityShortcutChord();}} else {// 省略部分代码......}} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {// 省略部分代码......}return;}
3、截屏事件处理 interceptScreenshotChord()
PhoneWindowManager#interceptScreenshotChord()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
private void interceptScreenshotChord() {/** if 判断参数介绍* mScreenshotChordEnabled 其值为mContext.getResources().getBoolean(com.android.internal.R.bool.config_enableScreenshotChord);* mScreenshotChordVolumeDownKeyTriggered 音量下键按下时值为true* mScreenshotChordPowerKeyTriggered 电源键按下时值为true* mA11yShortcutChordVolumeUpKeyTriggered 音量上(加)键抬起时为false , 按下时为true**/if (mScreenshotChordEnabled&& mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered&& !mA11yShortcutChordVolumeUpKeyTriggered) {// 获取当前时间final long now = SystemClock.uptimeMillis();// 当前时间小于 音量下键按下时间 + 150ms// 当前时间小于 power键按下时间 + 150msif (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS&& now <= mScreenshotChordPowerKeyTime+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {boolean inLongScreenshot = Settings.System.getIntForUser(mContext.getContentResolver(),LONGSCREENSHOT_SETTING, 0, UserHandle.USER_CURRENT_OR_SELF) == 1;if (hasInPowerUtrlSavingMode() || inLongScreenshot) {return;}// 长按音量下键,达到截屏条件,将该事件消费掉。mScreenshotChordVolumeDownKeyConsumed = true;// 防止触发 Power 键长按功能cancelPendingPowerKeyAction();// 设置截图的类型,TAKE_SCREENSHOT_FULLSCREEN 为全屏mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);// 截图的方式,(例如:按键、三指下滑 等等)mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);//执行 mScreenshotRunnablemHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());}}}
继续查看ScreenshotRunnable,此时会一步步向下调用,最终到SystemUI。
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
private class ScreenshotRunnable implements Runnable {private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;private int mScreenshotSource = SCREENSHOT_KEY_OTHER;public void setScreenshotType(int screenshotType) {mScreenshotType = screenshotType;}public void setScreenshotSource(int screenshotSource) {mScreenshotSource = screenshotSource;}@Overridepublic void run() {// 回调到 DisplayPolicy.javamDefaultDisplayPolicy.takeScreenshot(mScreenshotType, mScreenshotSource);}}
DisplayPolicy#takeScreenshot()
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
// 请求截取屏幕截图public void takeScreenshot(int screenshotType, int source) {if (mScreenshotHelper != null) {mScreenshotHelper.takeScreenshot(screenshotType,mStatusBar != null && mStatusBar.isVisibleLw(),mNavigationBar != null && mNavigationBar.isVisibleLw(),source, mHandler, null /* completionConsumer */);}}
继续往下看ScreenshotHelper#takeScreenshot()
frameworks/base/core/java/com/android/internal/util/ScreenshotHelper.java
// 请求截取屏幕截图public void takeScreenshot(final int screenshotType, final boolean hasStatus,final boolean hasNav, int source, @NonNull Handler handler,@Nullable Consumer<Uri> completionConsumer) {ScreenshotRequest screenshotRequest = new ScreenshotRequest(source, hasStatus, hasNav);takeScreenshot(screenshotType, SCREENSHOT_TIMEOUT_MS, handler, screenshotRequest,completionConsumer);}//到了 Binder调用环节, 此为客户端, 服务端为SystemUI中的 TakeScreenshotServiceprivate void takeScreenshot(final int screenshotType, long timeoutMs, @NonNull Handler handler,ScreenshotRequest screenshotRequest, @Nullable Consumer<Uri> completionConsumer) {synchronized (mScreenshotLock) {final Runnable mScreenshotTimeout = () -> {synchronized (mScreenshotLock) {if (mScreenshotConnection != null) {// 在获取屏幕截图捕获响应之前超时Log.e(TAG, "Timed out before getting screenshot capture response");// 重置连接resetConnection();// 通知截屏错误notifyScreenshotError();}}if (completionConsumer != null) {completionConsumer.accept(null);}};Message msg = Message.obtain(null, screenshotType, screenshotRequest);Handler h = new Handler(handler.getLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case SCREENSHOT_MSG_URI:if (completionConsumer != null) {completionConsumer.accept((Uri) msg.obj);}handler.removeCallbacks(mScreenshotTimeout);break;case SCREENSHOT_MSG_PROCESS_COMPLETE:synchronized (mScreenshotLock) {resetConnection();}break;}}};msg.replyTo = new Messenger(h);if (mScreenshotConnection == null || mScreenshotService == null) {// 一个标准的Service连接// config_screenshotServiceComponent == com.android.systemui/com.android.systemui.screenshot.TakeScreenshotServicefinal ComponentName serviceComponent = ComponentName.unflattenFromString(mContext.getResources().getString(com.android.internal.R.string.config_screenshotServiceComponent));final Intent serviceIntent = new Intent();serviceIntent.setComponent(serviceComponent);ServiceConnection conn = new ServiceConnection() {@Override// 当Service连接成功之后public void onServiceConnected(ComponentName name, IBinder service) {synchronized (mScreenshotLock) {if (mScreenshotConnection != this) {return;}mScreenshotService = service;Messenger messenger = new Messenger(mScreenshotService);try {messenger.send(msg);} catch (RemoteException e) {Log.e(TAG, "Couldn't take screenshot: " + e);if (completionConsumer != null) {completionConsumer.accept(null);}}}}@Override// 当Service断开连接时public void onServiceDisconnected(ComponentName name) {synchronized (mScreenshotLock) {if (mScreenshotConnection != null) {resetConnection();// only log an error if we're still within the timeout periodif (handler.hasCallbacks(mScreenshotTimeout)) {handler.removeCallbacks(mScreenshotTimeout);notifyScreenshotError();}}}}};// bindServiceif (mContext.bindServiceAsUser(serviceIntent, conn,Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,UserHandle.CURRENT)) {mScreenshotConnection = conn;handler.postDelayed(mScreenshotTimeout, timeoutMs);}} else {// 如果已经连接则直接发送MessageMessenger messenger = new Messenger(mScreenshotService);try {messenger.send(msg);} catch (RemoteException e) {Log.e(TAG, "Couldn't take screenshot: " + e);if (completionConsumer != null) {completionConsumer.accept(null);}}handler.postDelayed(mScreenshotTimeout, timeoutMs);}}}
客户端通过向服务端发送 message 来将截屏任务交给 service,由 service 处理后面的操作。
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
private Handler mHandler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {// 获取客户端传的 Messenger 对象final Messenger callback = msg.replyTo;Consumer<Uri> uriConsumer = uri -> {Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);try {/ /Messenger 双向通信,在服务端用远程客户端的 Messenger 对象给客户端发送信息callback.send(reply);} catch (RemoteException e) {}};Runnable onComplete = () -> {Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);try {callback.send(reply);} catch (RemoteException e) {}};// 判断用户的设备是否为解锁状态// 如果用户的存储被锁定,我们没有地方存储截图,所以跳过它,而不是显示一个误导性的动画和错误通知。if (!mUserManager.isUserUnlocked()) {Log.w(TAG, "Skipping screenshot because storage is locked!");post(() -> uriConsumer.accept(null));post(onComplete);return;}ScreenshotHelper.ScreenshotRequest screenshotRequest =(ScreenshotHelper.ScreenshotRequest) msg.obj;mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));switch (msg.what) {case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: // 全屏截图// 我们在PhoneWindowManager传入的type为全屏截图,所以需要执行全屏截图流程mScreenshot.takeScreenshot(uriConsumer, onComplete);break;case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: // 区域截图mScreenshot.takeScreenshot(uriConsumer, onComplete);break;case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(screenshotRequest.getBitmapBundle());Rect screenBounds = screenshotRequest.getBoundsInScreen();Insets insets = screenshotRequest.getInsets();int taskId = screenshotRequest.getTaskId();int userId = screenshotRequest.getUserId();ComponentName topComponent = screenshotRequest.getTopComponent();mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,taskId, userId, topComponent, uriConsumer, onComplete);break;default:Log.d(TAG, "Invalid screenshot option: " + msg.what);}}};
TakeScreenshotService调用GlobalScreenshot.java的takeScreenshot();
GlobalScreenshot#takeScreenshot()
// GlobalScreenshot.java/***截取当前显示的屏幕截图并显示动画。.*/private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {// copy the input Rect, since SurfaceControl.screenshot can mutate itRect screenRect = new Rect(crop);int rot = mDisplay.getRotation();int width = crop.width();int height = crop.height();takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,Insets.NONE, true);}private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,Insets screenInsets, boolean showFlash) {// 此方法会清除上一次的截图信息--连续截图行为dismissScreenshot("new screenshot requested", true);mScreenBitmap = screenshot;if (mScreenBitmap == null) {// 如果没有Bitmap则报告错误信息mNotificationsController.notifyScreenshotError(R.string.screenshot_failed_to_capture_text);finisher.accept(null);mOnCompleteRunnable.run();return;}if (!isUserSetupComplete()) {// 用户设置尚未完成,不应该向用户展示 分享和编辑 , 只显示一个Toast并保存图片saveScreenshotAndToast(finisher);return;}// OptimizationsmScreenBitmap.setHasAlpha(false);mScreenBitmap.prepareToDraw();onConfigChanged(mContext.getResources().getConfiguration());if (mDismissAnimation != null && mDismissAnimation.isRunning()) {mDismissAnimation.cancel();}// 获取焦点setWindowFocusable(true);// 开始截图后动画startAnimation(finisher, screenRect, screenInsets, showFlash);}/*** 截屏后开始动画*/private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,boolean showFlash) {if (mScreenshotIng == false) {//unisoc: Modify for bug1360276mScreenshotIng = true;// 如果开启了省电模式,显示 toast,以便有一些视觉提示已截取屏幕截图PowerManager powerManager =(PowerManager) mContext . getSystemService (Context.POWER_SERVICE);if (powerManager.isPowerSaveMode()) {Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();}mScreenshotHandler.post(() -> {if (!mScreenshotLayout.isAttachedToWindow()) {// mScreenshotLayout是截屏的缩略图的父View// mScreenshotLayout 在 GlobalScreenshot.java 的构造方法中初始化。对应布局文件:global_screenshot.xmlmWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);}// 动画相关的ViewmScreenshotAnimatedView.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));setAnimatedViewSize(screenRect.width(), screenRect.height());// 显示动画何时开始mScreenshotAnimatedView.setVisibility(View.GONE);//缩略图显示的View,将native层返回的Bitmap加载到此View上mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));// 使静态预览不可见(消失),以便我们可以在屏幕上查询其位置mScreenshotPreview.setVisibility(View.INVISIBLE);mScreenshotHandler.post(() -> {mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);// 创建动画mScreenshotAnimation =createScreenshotDropInAnimation(screenRect, showFlash);// 保存截图saveScreenshotInWorkerThread(finisher, new ActionsReadyListener () {@Overridevoid onActionsReady (SavedImageData imageData) {showUiOnActionsReady(imageData);mScreenshotIng = false;}});// 播放快门声音以通知我们已截屏mCameraSound.play(MediaActionSound.SHUTTER_CLICK);if (mScreenshotPreview.isAttachedToWindow()) {mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);mScreenshotPreview.buildLayer();}// 开始执行动画mScreenshotAnimation.start();});});}}/*** 创建一个新的工作线程并将屏幕截图保存到媒体存储*/private void saveScreenshotInWorkerThread(Consumer<Uri> finisher, @Nullable ActionsReadyListener actionsReadyListener) {SaveImageInBackgroundData data = new SaveImageInBackgroundData();data.image = mScreenBitmap; // native 层返回的 Bitmapdata.finisher = finisher;data.mActionsReadyListener = actionsReadyListener;if (mSaveInBgTask != null) {// just log success/failure for the pre-existing screenshot// 只需记录预先存在的屏幕截图的成功失败mSaveInBgTask.setActionsReadyListener(new ActionsReadyListener() {@Overridevoid onActionsReady(SavedImageData imageData) {logSuccessOnActionsReady(imageData);}});}// 截图的一些信息存储在 SaveImageInBackgroundTask 中构建mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);mSaveInBgTask.execute();}
到此截屏流程完毕,可以查看下截图的View的xml文件:global_screenshot.xml
frameworks/base/packages/SystemUI/res/layout/global_screenshot.xml
<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/global_screenshot_frame"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/global_screenshot_actions_background"android:layout_height="@dimen/screenshot_bg_protection_height"android:layout_width="match_parent"android:layout_gravity="bottom"android:alpha="0.0"android:src="@drawable/screenshot_actions_background_protection"/><!--截屏动画相关的View --><ImageViewandroid:id="@+id/global_screenshot_animated_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="top|start"android:visibility="gone"android:elevation="@dimen/screenshot_preview_elevation"android:background="@drawable/screenshot_rounded_corners" /><ImageViewandroid:id="@+id/global_screenshot_flash"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"android:elevation="@dimen/screenshot_preview_elevation"android:src="@android:color/white"/><com.android.systemui.screenshot.ScreenshotSelectorViewandroid:id="@+id/global_screenshot_selector"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"android:pointerIcon="crosshair"/><!-- 此处包含了一个layout, 而缩略图的View就在此layout中,截屏右上角的关闭缩略图按钮 也在此layout中 --><include layout="@layout/global_screenshot_static"/>
</FrameLayout>
相关文章:
Android 10.0 截屏流程
通常未通过特殊定制的 Android 系统,截屏都是经过同时按住音量下键和电源键来截屏。本篇文章就只讨论使用这些特殊按键来进行截屏。 这里我们就要明白事件是在哪里进行分发拦截的。通过源码的分析,我们发现是在PhoneWindowManager.java 中。 PhoneWindow…...

Axure零基础深入浅出的讲解
在当今的互联网产品设计领域,原型设计已经成为了产品经理、设计师和开发者之间沟通的桥梁。而Axure作为一款功能强大、灵活易用的原型设计工具,正是很多产品经理的得力助手。无论你是产品经理新手,还是资深设计师,Axure都能帮助你…...

PyTorch求导相关
PyTorch是动态图,即计算图的搭建和运算是同时的,随时可以输出结果;而TensorFlow是静态图。 在pytorch的计算图里只有两种元素:数据(tensor)和 运算(operation) 运算包括了…...

Halcon基础-瓶盖带角度的OCR批量识别
Halcon基础-OCR识别 1、OCR识别素材2、创建路径文件3、Halcon代码实现4、运行效果5、资源获取 1、OCR识别素材 这里我准备了7张不同角度的OCR图片,如下所示: 2、创建路径文件 按照下图所示创建全部文件夹和文件: 01用来存放OCR识别原图 c…...

php语法学习
启动php 进入软件 打开文件:编写代码 $php true; $java false; var_dump($php);//输出变量细节 var_dump($java) 字符串 注意可以使用双引号也可以使用单引号 测试 $php "最好学web语言"; $java 脱胎于c语言; var_dump($php);//输出变量细节 var…...

JavaWeb合集22-Apache POI
二十二、Apache POI Apache POI是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用POI在Java 序中对Miscrosoft Office各种文件进行读写操作。一般情况下,POI都是用于操作Excel文件。 使用场景:银行网银系统导出…...

DDD重构-实体与限界上下文重构
DDD重构-实体与限界上下文重构 概述 DDD 方法需要不同类型的类元素,例如实体或值对象,并且几乎所有这些类元素都可以看作是常规的 Java 类。它们的总体结构是 Name: 类的唯一名称 Properties:属性 Methods: 控制变量的变化和添加行为 一…...

MATLAB Simulink (二)高速跳频通信系统
MATLAB & Simulink (二)高速跳频通信系统 写在前面1 系统原理1.1 扩频通信系统理论基础1.1.1 基本原理1.1.2 扩频通信系统处理增益和干扰容限1.1.3 各种干扰模式下抗干扰性能 1.2 高速跳频通信系统理论基础1.2.1 基本原理1.2.2 物理模型 2 方案设计2…...

智能合约分享
智能合约练习 一、solidity初学者经典示例代码: 1.存储和检索数据: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // 声明 Solidity 编译器版本// 定义一个名为 SimpleStorage 的合约 contract SimpleStorage {// 声明一个公共状态变量 d…...

【MR开发】在Pico设备上接入MRTK3(二)——在Unity中配置Pico SDK
上一篇文档介绍了 【MR开发】在Pico设备上接入MRTK3(一)在Unity中导入MRTK3依赖 下面将介绍在Unity中导入Pcio SDK的具体步骤 在Unity中导入Pico SDK 当前Pico SDK版本 Unity交互SDK git仓库: https://github.com/Pico-Developer/PICO-Un…...

【Java】探秘正则表达式:深度解析与精妙运用
目录 引言 一、基本概念 1.1 元字符 1.2 预定义字符类 1.3 边界匹配符 1.4 数量标识符 1.5 捕获与非捕获分组 二、Java中的正则表达式支持 三、正则表达式的使用示例 3.1 匹配字符串 3.2 替换字符串 3.3 分割字符串 3.4 使用Pattern和Matcher 3.5 捕获组和后向…...
2.6.ReactOS系统中从内核中发起系统调用
2.6.ReactOS系统中从内核中发起系统调用 2.6.ReactOS系统中从内核中发起系统调用 文章目录 2.6.ReactOS系统中从内核中发起系统调用前言 前言 上面我们已经可以看到用户空间(R3)进行系统调用的全过程即两种方法的具体实现。 系统调用一般时从R3发起的…...
chat_gpt回答:python获取当前utc时间,将xml里时间tag里的值修改为当前时间
你可以使用 lxml 库来读取、修改 XML 文件中的某个标签的值,并将其保存为新的 XML 文件。以下是一个示例代码,展示如何获取当前的 UTC 时间,并将 XML 文件中的某个时间标签修改为当前时间。 示例代码: from lxml import etree f…...

机器学习-语言分析
机器学习 1.1人工智能概述 1.2.1 机器学习与人工智能,深度学习 深度学习->机器学习->人工智能; 人工智能:1950,实现自动下棋,人机对弈,达特茅斯会议->人工智能的起点,1956年8月。克劳…...

Oracle 常见索引扫描方式概述,哪种索引扫描最快!
一.常见的索引扫描方式 INDEX RANGE SCANINDEX FAST FULL SCANINDEX FULL SCAN(MIN/MAX)INDEX FULL SCAN 二.分别模拟使用这些索引的场景 1.INDEX RANGE SCAN create table t1 as select rownum as id, rownum/2 as id2 from dual connect by level<500000; create inde…...

字符串(3)_二进制求和_高精度加法
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 字符串(3)_二进制求和_高精度加法 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌 目…...
《神经网络:智能时代的核心技术》
《神经网络:智能时代的核心技术》 一、神经网络的诞生与发展二、神经网络的结构与工作原理(一)神经元模型(二)神经网络训练过程 三、神经网络的应用领域(一)信息领域(二)…...
pdf内容三张以上转图片,使用spire.pdf.free
一、依赖 <spire.pdf.free.version>9.13.0</spire.pdf.free.version><itextpdf.version>5.5.13</itextpdf.version><dependency><groupId>e-iceblue</groupId><artifactId>spire.pdf.free</artifactId><version>$…...
游戏、软件、开源项目和资讯
游戏 标题链接【白嫖正版游戏】IT之家喜加一website 软件 标题链接【白嫖正版软件】反斗限免website 开源项目 标题链接【Luxirty Search】基于Google搜索结果,屏蔽内容农场Github【Video2X】图片/视频超分工具Github 新闻资讯 标题链接分享10个 Claude 3.5 …...

Acrel-1000变电站综合自动化系统及微机在化工企业中的应用方案
文:安科瑞郑桐 摘要:大型化工企业供配电具有的集约型特点,化工企业内35kV变电站和10kV变电所数量大、分布广,对于老的大多大型及中型化工企业而言,其变电站或变电所内高压电气设备为旧式继电保护装置,可靠…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...