【笔记】Android Settings 应用设置菜单的界面代码介绍
简介
Settings应用中,提供多类设置菜单入口,每个菜单内又有各模块功能的实现。
那么各个模块基于Settings 基础的界面Fragment去实现UI,层层按不同业务进行封装继承实现子类:
- DashboardFragment
- SettingsPreferenceFragment
功能设置页中的菜单又是通过Controller去实现业务并进行UI动态更新控制。
代码
基于 Android U 平台的实现进行介绍。
公用基类
DashboardFragment
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
package com.android.settings.dashboard;/*** Base fragment for dashboard style UI containing a list of static and dynamic setting items.*/
public abstract class DashboardFragment extends SettingsPreferenceFragmentimplements CategoryListener, Indexable, PreferenceGroup.OnExpandButtonClickListener,BasePreferenceController.UiBlockListener {public static final String CATEGORY = "category";private static final String TAG = "DashboardFragment";private static final long TIMEOUT_MILLIS = 50L;/*** Get a list of {@link AbstractPreferenceController} for this fragment.*/protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {return null;}
模块案例
继承关系:(自上而下,底层是父类,除了MobileNetwork,其他都是抽象类,直到Fragment)
- MobileNetworkSettings --- 移动网络设置
- AbstractMobileNetworkSettings
- RestrictedDashboardFragment
- DashboardFragment
- SettingsPreferenceFragment
- InstrumentedPreferenceFragment -- /com/android/settings/core/
- ObservablePreferenceFragment -- /frameworks/base/packages/SettingsLib
- PreferenceFragmentCompat -- classes.jar/androidx.preference
- Fragment
AbstractMobileNetworkSettings 是一个抽象类,用于提供移动网络设置相关的基本功能和行为。
RestrictedDashboardFragment 是在DashboardFragment的基础上添加了一些限制或额外的安全措施,以限制用户对某些设置或操作的访问或更改。可能会对一些敏感的设置进行限制,例如网络设置、安全设置等。也可能会对某些功能进行权限控制,只允许特定用户访问。
DashboardFragment 是基础的仪表盘样式 UI Fragment,用于显示静态和动态的设置项列表。通常不会加入对设置的限制,而是专注于提供用户友好的设置界面和功能。可能包含一些基本的设置项处理和展示逻辑,以便用户能够轻松地进行配置和操作。
MobileNetworkSettings 移动网络设置(界面逻辑)
packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java
界面布局在mobile_network_settings.xml
| API | Function |
|---|---|
| onPreferenceTreeClick | 定义子功能pref点击事件(override) |
| createPreferenceControllers | 创建子功能pref的控制器(override) |
| onAttach | 生命周期,use 各类 Controller(override) |
| onSubscriptionDetailChanged | 响应注册状态变化进行的操作 |
package com.android.settings.network.telephony;@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkSettings extends AbstractMobileNetworkSettings implementsMobileNetworkRepository.MobileNetworkCallback {private static final String LOG_TAG = "NetworkSettings";//处理子菜单点击事件/*** Invoked on each preference click in this hierarchy, overrides* PreferenceActivity's implementation. Used to make sure we track the* preference click events.*/@Overridepublic boolean onPreferenceTreeClick(Preference preference) {if (super.onPreferenceTreeClick(preference)) {return true;}final String key = preference.getKey();if (TextUtils.equals(key, BUTTON_CDMA_SYSTEM_SELECT_KEY)|| TextUtils.equals(key, BUTTON_CDMA_SUBSCRIPTION_KEY)) {if (mTelephonyManager.getEmergencyCallbackMode()) {startActivityForResult(new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),REQUEST_CODE_EXIT_ECM);mClickedPrefKey = key;}return true;}//【客制化】可通过else if 定制其他keyt的点击行为return false;}//创建各子菜单/功能选项的Controller@Overrideprotected List<AbstractPreferenceController> createPreferenceControllers(Context context) {if (!SubscriptionUtil.isSimHardwareVisible(context)) {finish();return Arrays.asList();}if (getArguments() == null) {Intent intent = getIntent();if (intent != null) {mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,MobileNetworkUtils.getSearchableSubscriptionId(context));Log.d(LOG_TAG, "display subId from intent: " + mSubId);} else {Log.d(LOG_TAG, "intent is null, can not get subId " + mSubId + " from intent.");}} else {mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,MobileNetworkUtils.getSearchableSubscriptionId(context));Log.d(LOG_TAG, "display subId from getArguments(): " + mSubId);}mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);mExecutor.execute(() -> {mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById(String.valueOf(mSubId));mMobileNetworkInfoEntity =mMobileNetworkRepository.queryMobileNetworkInfoBySubId(String.valueOf(mSubId));});return Arrays.asList(new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),this, mSubId),new RoamingPreferenceController(context, KEY_ROAMING_PREF, getSettingsLifecycle(),this, mSubId),new CallsDefaultSubscriptionController(context, KEY_CALLS_PREF,getSettingsLifecycle(), this),new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(),this),new MobileDataPreferenceController(context, KEY_MOBILE_DATA_PREF,getSettingsLifecycle(), this, mSubId),new ConvertToEsimPreferenceController(context, KEY_CONVERT_TO_ESIM_PREF,getSettingsLifecycle(), this, mSubId));}@Overridepublic void onAttach(Context context) {super.onAttach(context);if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {Log.d(LOG_TAG, "Invalid subId, get the default subscription to show.");SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);if (info == null) {Log.d(LOG_TAG, "Invalid subId request " + mSubId);return;}mSubId = info.getSubscriptionId();Log.d(LOG_TAG, "Show NetworkSettings fragment for subId" + mSubId);}Intent intent = getIntent();if (intent != null) {int updateSubscriptionIndex = intent.getIntExtra(Settings.EXTRA_SUB_ID,SubscriptionManager.INVALID_SUBSCRIPTION_ID);if (updateSubscriptionIndex != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {int oldSubId = mSubId;mSubId = updateSubscriptionIndex;// If the subscription has changed or the new intent does not contain the opt in// action,// remove the old discovery dialog. If the activity is being recreated, we will see// onCreate -> onNewIntent, so the dialog will first be recreated for the old// subscription// and then removed.if (updateSubscriptionIndex != oldSubId|| !MobileNetworkActivity.doesIntentContainOptInAction(intent)) {removeContactDiscoveryDialog(oldSubId);}// evaluate showing the new discovery dialog if this intent contains an action to// show the// opt-in.if (MobileNetworkActivity.doesIntentContainOptInAction(intent)) {showContactDiscoveryDialog();}}}final DataUsageSummaryPreferenceController dataUsageSummaryPreferenceController =use(DataUsageSummaryPreferenceController.class);if (dataUsageSummaryPreferenceController != null) {dataUsageSummaryPreferenceController.init(mSubId);}use(MobileNetworkSwitchController.class).init(mSubId);use(CarrierSettingsVersionPreferenceController.class).init(mSubId);use(BillingCyclePreferenceController.class).init(mSubId);use(MmsMessagePreferenceController.class).init(mSubId);use(AutoDataSwitchPreferenceController.class).init(mSubId);use(DisabledSubscriptionController.class).init(mSubId);use(DeleteSimProfilePreferenceController.class).init(mSubId, this,REQUEST_CODE_DELETE_SUBSCRIPTION);use(DisableSimFooterPreferenceController.class).init(mSubId);use(NrDisabledInDsdsFooterPreferenceController.class).init(mSubId);final MobileDataPreferenceController mobileDataPreferenceController =use(MobileDataPreferenceController.class);if (mobileDataPreferenceController != null) {mobileDataPreferenceController.init(getFragmentManager(), mSubId,mSubscriptionInfoEntity, mMobileNetworkInfoEntity);mobileDataPreferenceController.setWifiPickerTrackerHelper(new WifiPickerTrackerHelper(getSettingsLifecycle(), context,null /* WifiPickerTrackerCallback */));}final RoamingPreferenceController roamingPreferenceController =use(RoamingPreferenceController.class);if (roamingPreferenceController != null) {roamingPreferenceController.init(getFragmentManager(), mSubId,mMobileNetworkInfoEntity);}use(ApnPreferenceController.class).init(mSubId);use(CarrierPreferenceController.class).init(mSubId);use(DataUsagePreferenceController.class).init(mSubId);use(PreferredNetworkModePreferenceController.class).init(mSubId);use(EnabledNetworkModePreferenceController.class).init(mSubId);use(DataServiceSetupPreferenceController.class).init(mSubId);use(Enable2gPreferenceController.class).init(mSubId);use(CarrierWifiTogglePreferenceController.class).init(getLifecycle(), mSubId);final WifiCallingPreferenceController wifiCallingPreferenceController =use(WifiCallingPreferenceController.class).init(mSubId);final OpenNetworkSelectPagePreferenceController openNetworkSelectPagePreferenceController =use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);final AutoSelectPreferenceController autoSelectPreferenceController =use(AutoSelectPreferenceController.class).init(getLifecycle(), mSubId).addListener(openNetworkSelectPagePreferenceController);use(NetworkPreferenceCategoryController.class).init(mSubId).setChildren(Arrays.asList(autoSelectPreferenceController));mCdmaSystemSelectPreferenceController = use(CdmaSystemSelectPreferenceController.class);mCdmaSystemSelectPreferenceController.init(getPreferenceManager(), mSubId);mCdmaSubscriptionPreferenceController = use(CdmaSubscriptionPreferenceController.class);mCdmaSubscriptionPreferenceController.init(getPreferenceManager(), mSubId);final VideoCallingPreferenceController videoCallingPreferenceController =use(VideoCallingPreferenceController.class).init(mSubId);use(CallingPreferenceCategoryController.class).setChildren(Arrays.asList(wifiCallingPreferenceController, videoCallingPreferenceController));use(Enhanced4gLtePreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(Enhanced4gCallingPreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(Enhanced4gAdvancedCallingPreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(ContactDiscoveryPreferenceController.class).init(getParentFragmentManager(), mSubId);use(NrAdvancedCallingPreferenceController.class).init(mSubId);use(TransferEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);final ConvertToEsimPreferenceController convertToEsimPreferenceController =use(ConvertToEsimPreferenceController.class);if (convertToEsimPreferenceController != null) {convertToEsimPreferenceController.init(mSubId, mSubscriptionInfoEntity);}List<AbstractSubscriptionPreferenceController> subscriptionPreferenceControllers =useAll(AbstractSubscriptionPreferenceController.class);for (AbstractSubscriptionPreferenceController controller :subscriptionPreferenceControllers) {controller.init(mSubId);}}private void onSubscriptionDetailChanged() {if (mSubscriptionInfoEntity != null) {/*** Update the title when SIM stats got changed*/final Consumer<Activity> renameTitle = activity -> {if (activity != null && !activity.isFinishing()) {if (activity instanceof SettingsActivity) {((SettingsActivity) activity).setTitle(mSubscriptionInfoEntity.uniqueName);}}};ThreadUtils.postOnMainThread(() -> {renameTitle.accept(getActivity());redrawPreferenceControllers();});}}//界面布局在mobile_network_settings.xml@Overrideprotected int getPreferenceScreenResId() {return R.xml.mobile_network_settings;}} mobile_network_settings 布局
packages/apps/Settings/res/xml/mobile_network_settings.xml
- MobileNetworkSwitchController SIM卡移动网络总开关逻辑
- use_sim_switch 界面的资源key
- mobile_network_use_sim_on 开关名称title
以下仅展示部分功能选项/菜单:
<PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"xmlns:settings="http://schemas.android.com/apk/res-auto"android:key="mobile_network_pref_screen"><com.android.settings.widget.SettingsMainSwitchPreferenceandroid:key="use_sim_switch"android:title="@string/mobile_network_use_sim_on"settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/><PreferenceCategoryandroid:key="enabled_state_container"android:title="@string/summary_placeholder"settings:controller="com.android.settings.network.telephony.DisabledSubscriptionController"android:layout="@layout/preference_category_no_label"><!--智能数据切换开关--><SwitchPreferenceandroid:key="auto_data_switch"android:title="@string/auto_data_switch_title"android:summary="@string/auto_data_switch_summary"settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/><!--数据漫游开关--><com.android.settingslib.RestrictedSwitchPreferenceandroid:key="button_roaming_key"android:title="@string/roaming"android:persistent="false"android:summaryOn="@string/roaming_enable"android:summaryOff="@string/roaming_disable"settings:userRestriction="no_data_roaming"settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/><!--数据流量菜单入口--><Preferenceandroid:key="data_usage_summary"android:title="@string/mobile_data_usage_title"settings:controller="com.android.settings.network.telephony.DataUsagePreferenceController"/><!--网络模式列表选择--><ListPreferenceandroid:key="enabled_networks_key"android:title="@string/preferred_network_mode_title"android:summary="@string/preferred_network_mode_summary"android:entries="@array/enabled_networks_choices"android:entryValues="@array/enabled_networks_values"android:dialogTitle="@string/preferred_network_mode_dialogtitle"settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/><!--Network目录--><PreferenceCategoryandroid:key="network_operators_category_key"android:title="@string/network_operator_category"settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController"><!--自动选网开关--><SwitchPreferenceandroid:key="auto_select_key"android:title="@string/select_automatically"settings:controller="com.android.settings.network.telephony.gsm.AutoSelectPreferenceController"/><!--如果上述自动选网关闭,那么此手动选网菜单,可跳转到网络列表页--><Preferenceandroid:key="choose_network_key"android:title="@string/choose_network_title"settings:controller="com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController"/></PreferenceCategory><!--APN设置入口--><!--We want separate APN setting from reset of settings because we want user to change it with caution--><com.android.settingslib.RestrictedPreferenceandroid:key="telephony_apn_key"android:persistent="false"android:title="@string/mobile_network_apn_title"settings:allowDividerAbove="true"settings:keywords="@string/keywords_access_point_names"settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/></PreferenceCategory></PreferenceScreen>
相关文章:
【笔记】Android Settings 应用设置菜单的界面代码介绍
简介 Settings应用中,提供多类设置菜单入口,每个菜单内又有各模块功能的实现。 那么各个模块基于Settings 基础的界面Fragment去实现UI,层层按不同业务进行封装继承实现子类: DashboardFragmentSettingsPreferenceFragment 功…...
Symfony配置管理深度解析:构建可维护项目的秘诀
Symfony是一个高度灵活且功能丰富的PHP框架,它提供了一套强大的配置管理系统,使得开发者能够轻松定制和优化应用程序的行为。本文将深入探讨Symfony中的配置管理机制,包括配置的结构、来源、加载过程以及最佳实践。 一、配置管理的重要性 在…...
视频的宣传片二维码怎么做?扫码播放视频的制作教程
现在很多的宣传片会通过扫码的方式来展示,通过将视频生成二维码之后,其他人就可以扫码来查看视频内容,从而简化获取视频的过程,提升视频传播的效率及用户查看视频的便捷性。目前,日常生活和工作中就有视频二维码的应用…...
实用的网站
前端 精简CSS格式 Font Awesome 图标库 BootCDN 加速服务 LOGO U钙网 AI AI工具集 视频下载 B站视频解析下载...
Monorepo(单体仓库)与 MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南
🔥 个人主页:空白诗 文章目录 一、引言1. Monorepo 和 MultiRepo 简介2. 为什么选择 Monorepo? 二、Monorepo 和 MultiRepo 的区别1. 定义和概述2. 各自的优点和缺点3. 适用场景 三、Monorepo 的开发策略1. 版本控制2. 依赖管理3. 构建和发布…...
使用 PyTorch 创建的多步时间序列预测的 Encoder-Decoder 模型
Encoder-decoder 模型在序列到序列的自然语言处理任务(如语言翻译等)中提供了最先进的结果。多步时间序列预测也可以被视为一个 seq2seq 任务,可以使用 encoder-decoder 模型来处理。本文提供了一个用于解决 Kaggle 时间序列预测任务的 encod…...
开启IT世界的第一步:高考新生的暑期学习指南
目录 前言 了解IT领域 学习编程语言 实践项目 学习资源 阅读专业书籍 培养良好的学习习惯 结语 最后 - 投票 前言 七月的钟声敲响,各省的高考分数已揭晓,意味着一段紧张而又充满奋斗的旅程画上了句号。然而,高考的结束并不意味…...
软考系统架构师高效备考方法论
软考系统架构师高效备考方法论 本章总结的备考方法论也是希望能帮助更多的小伙伴高效的备考最终通过考试,这种考试个人感觉是尽量一次性考过, 要不然老拖着,虽然每年可以考两次,5月和11月,两次考试间隔5个月时间&#…...
【neo4j图数据库】入门实践篇
探索数据之间的奥秘:Neo4j图数据库引领新纪元 在数字化浪潮汹涌的今天,数据已成为企业最宝贵的资产之一。然而,随着数据量的爆炸性增长和数据关系的日益复杂,传统的关系型数据库在处理诸如社交网络、推荐系统、生物信息学等高度互…...
【TS】TypeScript 原始数据类型深度解析
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 TypeScript 原始数据类型深度解析一、引言二、基础原始数据类型2.1 boolean2.2 …...
怎么样调整分类的阈值
调整分类模型的阈值是改变模型对正负类的预测标准的一种方法,常用于提高精确率、召回率或者其他性能指标。以下是如何调整分类阈值的步骤和方法: PS:阈值是针对预测概率(表示样本属于某个特定类别的可能性)来说的 调…...
java+mysql教师管理系统
完整源码地址 教师信息管理系统使用命令行交互的方式及数据库连接实现教师信息管理系统,该系统旨在实现教师信息的管理,并根据需要进行教师信息展示。该软件的功能有如下功能 (1)基本信息管理(教师号、姓名、性别、出生年月、职称、学历、学位、教师类型…...
PDF文档如何统计字数,统计PDF文档字数的方法有哪些?
在平时使用pdf阅读或者是处理文档的时候,常常需要统计文档的字数。pdf在查看文字时其实很简单。 PDF文档是一种常见的电子文档格式,如果需要对PDF文档中的字数进行统计,可以使用以下方法: Adobe Acrobat DC:Adobe Ac…...
在Python asyncio中如何识别协程是否被block了
现在asyncio在Python中的使用越来越广泛了,但是很多人对于协程(corotine)的一些使用方式还不太熟悉。在这篇文章中,我将会介绍如何识别协程是否被block了,并以常用的HTTP网络库requests/httpx为例来说明如何避免协程被block的问题。 为什么协程会被block 在Python中,可…...
Hyper-V虚拟机固定IP地址(手把手教设置)
链接虚拟机修改网络配置文件 输入指令 sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0 然后 输入 按 i 键 再按回车 (enter) 进入编辑模式 修改配置(这几项)其中 IPADDR 就是你想给虚拟机固定的 IP 地址 多台的话只需要修改这个IP 就行其他不变 BOOTPROTO=static…...
以 Vue 3 项目为例,多个请求下如何全局封装 Loading 的展示与关闭?其中大有学问!
大家好,我是CodeQi! 项目开发中,Loading 的展示与关闭是非常关键的用户体验设计。 当我们的应用需要发起多个异步请求时,如何有效地管理全局 Loading 状态,保证用户在等待数据加载时能有明确的反馈,这是一个值得深入探讨的问题。 本文将以 Vue 3 项目为例,详细讲解如…...
Node.js学习(一)
Node.js安装与入门案例: 需求:点击按钮,请求本地目录指定文件的内容,并显示在页面上 刚入门肯定想着直接写相对路径请求指定路径数据就行了,可是会发现不行。 网页运行在浏览器端,通常后续要发布…...
Spring Data JPA使用及实现原理总结
Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…...
【C语言】extern 关键字
在C语言中,extern关键字用于声明一个变量或函数是定义在另一个文件中的。它使得在多个文件之间共享变量或函数成为可能。extern关键字常见于大型项目中,通常用于声明全局变量或函数,这些变量或函数的定义位于其他文件中。 基本用法 变量声明…...
Linux--V4L2应用程序开发(二)改变亮度
一、思路流程 创建一个新线程用来控制亮度,线程通过读取用户输入来增加或减少亮度值,并使用 ioctl 函数将新亮度值设置到视频设备。 二、代码 /*创建线程来控制亮度*/ pthread_t thread; pthread_create(&thread, NULL, thread_brightness_contrl…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...
