当前位置: 首页 > news >正文

Android 10.0 Settings 加载流程

一、系统设置首页

代码路径:packages/app/Settings/

1 主界面加载:
    <!-- Alias for launcher activity only, as this belongs to each profile. --><activity-alias android:name="Settings"android:label="@string/settings_label_launcher"android:launchMode="singleTask"android:targetActivity=".homepage.SettingsHomepageActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/></activity-alias>

Settings的主界面是Settings.java,但是从Settings.java来看,除了大量的静态类继承SettingsActivity,就无其他有效信息了。但看其xml定义可以发现targetActivity属性,实质应是SettingsHomepageActivity.java。
先看其xml配置:

        <activity android:name=".homepage.SettingsHomepageActivity"android:label="@string/settings_label_launcher"android:theme="@style/Theme.Settings.Home"android:launchMode="singleTask"><intent-filter android:priority="1"><action android:name="android.settings.SETTINGS" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"android:value="true" /></activity>

SettingsHomepageActivity.java,主要从onCreate()方法开始:

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.settings_homepage_container);final View root = findViewById(R.id.settings_homepage_container);root.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);setHomepageContainerPaddingTop();final Toolbar toolbar = findViewById(R.id.search_action_bar);FeatureFactory.getFactory(this).getSearchFeatureProvider().initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);final ImageView avatarView = findViewById(R.id.account_avatar);final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);getLifecycle().addObserver(avatarViewMixin);if (!getSystemService(ActivityManager.class).isLowRamDevice()) {// Only allow contextual feature on high ram devices.showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);}showFragment(new TopLevelSettings(), R.id.main_content);((FrameLayout) findViewById(R.id.main_content)).getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
}

可以看到主界面的layout为settings_homepage_container.xml:

<androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/settings_homepage_container"android:fitsSystemWindows="true"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.core.widget.NestedScrollViewandroid:id="@+id/main_content_scrollable_container"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior"><LinearLayoutandroid:id="@+id/homepage_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:descendantFocusability="blocksDescendants"><FrameLayoutandroid:id="@+id/contextual_cards_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="@dimen/contextual_card_side_margin"android:layout_marginEnd="@dimen/contextual_card_side_margin"/><FrameLayoutandroid:id="@+id/main_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:animateLayoutChanges="true"android:background="?android:attr/windowBackground"/></LinearLayout></androidx.core.widget.NestedScrollView><com.google.android.material.appbar.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><include layout="@layout/search_bar"/></com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

主界面布局中主要包含三部分:两个FrameLayout,一个顶部快捷搜索栏。其中Id为main_content的FrameLayout就是用来显示主设置内容的,即Settings的一级菜单项界面。.homepage.SettingsHomepageActivity 中的逻辑并不复杂,直接加载了TopLevelSettings这个Fragment。

showFragment(new TopLevelSettings(), R.id.main_content);

TopLevelSettings通过AndroidX的Preference来展示设置项列表,设置项列表的内容通过静态配置+动态添加的方式获取。
后面分开分析:SettingsActivity.java、DashboardFragment.java。

2 SettingsActivity.java

Settings 继承了 SettingsActivity,有着大量的静态类,但其中并没有实现任何逻辑,那它是怎么加载到自己应有的布局的呢?
其实这些Activity的逻辑都是在SettingsActivity中实现。
在父类SettingsActivity的onCreate()中:

    @Override  protected void onCreate(Bundle savedState) {  super.onCreate(savedState);  long startTime = System.currentTimeMillis();  //工厂类实现方法com.android.settings.overlay.FeatureFactoryImpl.java  final FeatureFactory factory = FeatureFactory.getFactory(this);  //获取菜单信息的工厂类,实现类为DashboardFeatureProviderImpl.java  mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);  mMetricsFeatureProvider = factory.getMetricsFeatureProvider();  // 第一步    从intent信息中获取<meta-data/>标签名为"com.android.settings.FRAGMENT_CLASS"的值(下文用于加载Fragment的类名)  getMetaData();  // 第二步final Intent intent = getIntent();if (intent.hasExtra(EXTRA_UI_OPTIONS)) {getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));}//获取上面getMetaData()得到的类名  final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);  //是否为快捷进入方式(如从其它的应用进入Settings的某个设置项)  mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||  intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);  ... ...  if (savedState != null) {  ... ...  } else {  //  第三步   加载布局  launchSettingFragment(initialFragmentName, isSubSettings, intent);  }  ... ...  }

第一步:
首先通过getMetaData()获取该Activity在manifest中配置的fragment, 并赋值给mFragmentClass。

    private void getMetaData() {try {ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),PackageManager.GET_META_DATA);if (ai == null || ai.metaData == null) return;mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);} catch (NameNotFoundException nnfe) {// No recoveryLog.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());}}

第二步:
通过getIntent()方法、getStartingFragmentClass()方法筛选出要启动的Fragment。
第三步:
通过launchSettingFragment()启动对应Fragment,这里的initialFragmentName参数就是第二步Intent中包含的EXTRA_SHOW_FRAGMENT参数,mFragmentClass不为空的情况下传入的就是mFragmentClass。

3 DashboardFragment.java

通过上面知道,SettingsHomepageActivity 直接加载了TopLevelSettings这个Fragment。而该Fragment继承了DashboardFragment,先来看TopLevelSettings的构造方法:

    public TopLevelSettings() {final Bundle args = new Bundle();// Disable the search icon because this page uses a full search view in actionbar.args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false);setArguments(args);}

可以看到构造方法中仅设置了个标志位,再根据framgments生命周期先来看onAttach()方法:

    @Overridepublic void onAttach(Context context) {super.onAttach(context);use(SupportPreferenceController.class).setActivity(getActivity());}

调用父类DashboardFragment.java的onAttach()方法,此方法主要是完成mPreferenceControllers的加载。
接着看onCreate()方法,因为TopLevelSettings未重写父类的方法,所以直接看父类DashboardFragment的onCreate()方法。

    @Overridepublic void onCreate(Bundle icicle) {super.onCreate(icicle);// Set ComparisonCallback so we get better animation when list changes.getPreferenceManager().setPreferenceComparisonCallback(new PreferenceManager.SimplePreferenceComparisonCallback());if (icicle != null) {// Upon rotation configuration change we need to update preference states before any// editing dialog is recreated (that would happen before onResume is called).updatePreferenceStates();}}

根据log定位发现,其后调用DashboardFragment.java的onCreatePreferences()方法:这里我也不知道怎么调用到这来的,哈哈。

    @Overridepublic void onCreatePreferences(Bundle savedInstanceState, String rootKey) {refreshAllPreferences(getLogTag());}/*** Refresh all preference items, including both static prefs from xml, and dynamic items from* DashboardCategory.*/private void refreshAllPreferences(final String TAG) {final PreferenceScreen screen = getPreferenceScreen();// First remove old preferences.if (screen != null) {// Intentionally do not cache PreferenceScreen because it will be recreated later.screen.removeAll();}// Add resource based tiles.displayResourceTiles();refreshDashboardTiles(TAG);final Activity activity = getActivity();if (activity != null) {Log.d(TAG, "All preferences added, reporting fully drawn");activity.reportFullyDrawn();}updatePreferenceVisibility(mPreferenceControllers);}

以看到此方法主要是用来加载显示的preference items,主要分为两部分,一个是静态xml定义的prefs(调用displayResourceTiles()方法),另一部分是从DashboardCategory动态加载(调用refreshDashboardTiles(TAG)方法,其中TAG为 “TopLevelSettings”)。
displayResourceTiles()
此方法主要是从xml资源文件中加载显示prefs:

    /*** Displays resource based tiles.*/private void displayResourceTiles() {final int resId = getPreferenceScreenResId();if (resId <= 0) {return;}addPreferencesFromResource(resId);final PreferenceScreen screen = getPreferenceScreen();screen.setOnExpandButtonClickListener(this);mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach(controller -> controller.displayPreference(screen));}

首先调用getPreferenceScreenResId()方法获取所要加载的xml的ID:

    @Overrideprotected abstract int getPreferenceScreenResId();

最终回调用到子类TopLevelSettings.java的getPreferenceScreenResId()方法:

    @Overrideprotected int getPreferenceScreenResId() {return R.xml.top_level_settings;}

此主要是调用androidX Preference的addPreferencesFromResource()方法。此方法主要是将preferenceScreen下所有Preference添加到ArrayList中,然后再根据此集合构建生成PreferenceGroupAdapter,最后将此adapter设置到listview中,完成数据绑定,从而完成界面加载。在这里就要明白mPreferenceControllers是什么,在哪初始化的?
我们很快就可以找到:在onAttach()中添加的。

        final List<AbstractPreferenceController> controllers = new ArrayList<>();// Load preference controllers from codefinal List<AbstractPreferenceController> controllersFromCode =createPreferenceControllers(context);// Load preference controllers from xml definitionfinal List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper.getPreferenceControllersFromXml(context, getPreferenceScreenResId());// Filter xml-based controllers in case a similar controller is created from code already.final List<BasePreferenceController> uniqueControllerFromXml =PreferenceControllerListHelper.filterControllers(controllersFromXml, controllersFromCode);// Add unique controllers to list.if (controllersFromCode != null) {controllers.addAll(controllersFromCode);}controllers.addAll(uniqueControllerFromXml);// And wire up with lifecycle.final Lifecycle lifecycle = getSettingsLifecycle();uniqueControllerFromXml.stream().filter(controller -> controller instanceof LifecycleObserver).forEach(controller -> lifecycle.addObserver((LifecycleObserver) controller));mPlaceholderPreferenceController =new DashboardTilePlaceholderPreferenceController(context);controllers.add(mPlaceholderPreferenceController);for (AbstractPreferenceController controller : controllers) {addPreferenceController(controller);}

可以发现:

  1. 从代码中加载preference controllers,调用createPreferenceControllers()方法;
  2. 从xml定义中加载preference controllers,调用getPreferenceControllersFromXml()方法。
  3. 过滤重复定义的controller等,赋值填充mPreferenceControllers。

再回到displayResourceTiles()方法中的:

mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach(controller -> controller.displayPreference(screen));

此语句主要就是调用各个controller的displayPreference()方法。
以网络和互联网菜单项为例,xml中配置的controller为"com.android.settings.network.TopLevelNetworkEntryPreferenceController",查看TopLevelNetworkEntryPreferenceController.java发现,其内并未实现displayPreference()方法,查看继承关系:是继承BasePreferenceController的,接着查看BasePreferenceController中的displayPreference()方法。

    /*** Displays preference in this controller.*/@Overridepublic void displayPreference(PreferenceScreen screen) {super.displayPreference(screen);if (getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) {// Disable preference if it depends on another setting.final Preference preference = screen.findPreference(getPreferenceKey());if (preference != null) {preference.setEnabled(false);}}}

又是调用BasePreferenceController父类AbstractPreferenceController中的displayPreference:

    /*** Displays preference in this controller.*/public void displayPreference(PreferenceScreen screen) {final String prefKey = getPreferenceKey();if (TextUtils.isEmpty(prefKey)) {Log.w(TAG, "Skipping displayPreference because key is empty:" + getClass().getName());return;}if (isAvailable()) {setVisible(screen, prefKey, true /* visible */);if (this instanceof Preference.OnPreferenceChangeListener) {final Preference preference = screen.findPreference(prefKey);preference.setOnPreferenceChangeListener((Preference.OnPreferenceChangeListener) this);}} else {setVisible(screen, prefKey, false /* visible */);}}
  1. getPreferenceKey()获取preference的key,会调用到子类BasePreferenceController.java的getPreferenceKey()方法:
    @Overridepublic String getPreferenceKey() {return mPreferenceKey;}

而据上面分析到mPreferenceKey实质上即为xml中每个preference配置的android:key属性的值,即此处应为"top_level_network"。(以网络和互联网菜单项为例)
2. isAvailable();判断此preference是否可用即是否应该被显示。如果返回true,则被显示出来,反之则不被显示,最终也会调用到BasePreferenceController.java的isAvailable()方法:

    @Overridepublic final boolean isAvailable() {final int availabilityStatus = getAvailabilityStatus();return (availabilityStatus == AVAILABLE|| availabilityStatus == AVAILABLE_UNSEARCHABLE|| availabilityStatus == DISABLED_DEPENDENT_SETTING);}

注意:看这里的BasePreferenceController.java中的isAvailable()方法中的getAvailabilityStatus(),一直跟进去,会发现调用的是:BasePreferenceController子类TopLevelNetworkEntryPreferenceController.java的getAvailabilityStatus()方法:

    @Overridepublic int getAvailabilityStatus() {return Utils.isDemoUser(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE_UNSEARCHABLE;}
  1. 调用setVisible()方法设置是否可被显示:setVisible(screen, prefKey, true /* visible */);
    frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
    protected final void setVisible(PreferenceGroup group, String key, boolean isVisible) {final Preference pref = group.findPreference(key);if (pref != null) {pref.setVisible(isVisible);}}
  1. 判断controller是否实现了Preference.OnPreferenceChangeListener接口,是,则设置监听。
    综上,如果希望preference不被显示在界面上,可以通过实现相关preference的controller的getAvailabilityStatus()方法,使此方法的返回值不为AVAILABLE、AVAILABLE_UNSEARCHABLE、DISABLED_DEPENDENT_SETTING即可。
  2. 继续看查看BasePreferenceController.java的displayPreference()方法的剩余语句:
        if (getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) {// Disable preference if it depends on another setting.final Preference preference = screen.findPreference(getPreferenceKey());if (preference != null) {preference.setEnabled(false);}}

根据子类controller实现的getAvailabilityStatus()方法的返回值判断是否需要将此preference置为不可点击。
至此,DashboardFragment.java中displayResourceTiles()方法分析完成。

总结:

  1. Settings的主Activity实质实现是在SettingsHomepageActivity.java内;
  2. Settings的主界面设置item的显示是在fragment上,fragment为TopLevelSettings.java,加载显示的布局为top_level_settings.xml;
  3. Settings主界面设置项item的加载显示主要分为两部分,一部分是xml定义的静态加载,xml为top_level_settings.xml;一部分是DashboardCategory来获取动态加载。
  4. 每个设置项item均为一个preference,通过xml定义加载时,必须要有一个controller,可以是在xml中定义"settings:controller"属性声明,名称必须与类的包名路径相同;也可直接在相关fragment中实现createPreferenceControllers()方法去调用构造相关controller。此二者存其一即可。
  5. xml中配置preference时,必须定义”android:key“属性;
  6. 需要隐藏不显示某个设置项时,一是可以直接在xml中注释其定义;二是可以在相关设置项preference的controller类中实现getAvailabilityStatus()方法,使此方法的返回值不为AVAILABLE、AVAILABLE_UNSEARCHABLE、DISABLED_DEPENDENT_SETTING即可;
  7. 如果需要某个设置项不可点击,一是可以直接调用setEnabled()。二是可以在相关设置项preference的controller类中实现getAvailabilityStatus()方法,使此方法的返回值为DISABLED_DEPENDENT_SETTING即可。

相关文章:

Android 10.0 Settings 加载流程

一、系统设置首页 代码路径&#xff1a;packages/app/Settings/ 1 主界面加载&#xff1a; <!-- Alias for launcher activity only, as this belongs to each profile. --><activity-alias android:name"Settings"android:label"string/settings_la…...

mysql的索引、事务和存储引擎

目录 索引 索引的概念 索引的作用 作用 索引的副作用 创建索引 创建索引的原则和依据 索引的类型 创建索引 查看索引 删除索引 drop 主键索引 普通索引 添加普通索引 唯一索引 添加唯一索引 组合索引 添加组合索引 查询组合索引 全文索引 添加全文索引 …...

基于trace_id实现SpringCloudGateway网关的链路追踪

之前写的两篇关于基于 trace_id 的链路追踪的文章&#xff1a; 基于trace_id的链路追踪&#xff08;含Feign、Hystrix、线程池等场景&#xff09;基于trace_id的链路追踪&#xff08;ForkJoinPool场景&#xff09; 一、引言 在之前的文章中&#xff0c;我们讨论了基于 trace…...

Windows 11 version 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2024)

Windows 11 version 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2024) Windows 11, version 22H2&#xff0c;企业版 arm64 x64 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者…...

【C语言】动态内存管理(上)

文章目录 前言1.为什么要存在动态内存2. malloc和free2.1 malloc2.2 free2.3 使用实例&#xff08;malloc和free&#xff09; 3. calloc3.1 calloc例子 前言 本文开始将开始学习C语言中一个比较重要的知识点或者是操作——动态内存管理。由于本次的知识比较重要&#xff0c;为…...

【BUG】已解决:ModuleNotFoundError: No module named‘ pip‘

已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰…...

网络安全-网络安全及其防护措施11

51.网络容量规划 网络容量规划的概念和重要性 网络容量规划&#xff1a; 是指根据业务需求和预期增长&#xff0c;合理规划和设计网络的带宽、设备和资源&#xff0c;以满足未来网络流量和服务质量的需求。通过有效的网络容量规划&#xff0c;确保网络性能稳定和用户体验良好…...

使用IDEA编写lua脚本并运行

下载lua https://github.com/rjpcomputing/luaforwindows/releases 是否创建桌面快捷方式&#xff1a;我们的目标是使用IDEA编写lua脚本&#xff0c;所以不需要勾选。后面需要的话&#xff0c;可以到安装目录下手动创建快捷方式 环境变量自动配置 安装后会自动配置好环境变量…...

CentOS 7 安装MySQL 5.7.30

CentOS 7 安装MySQL卸载&#xff08;离线安装&#xff09; 安装配置MySQL之前先查询是否存在&#xff0c;如存在先卸载再安装 rpm -qa|grep -i mysql rpm -qa|grep -i mariadb rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x86_64如下命令找到直接 rm -rf 删除&#xff08;删除…...

Bash 学习摘录

文章目录 1、变量和参数的介绍&#xff08;1&#xff09;变量替换$(...) &#xff08;2&#xff09;特殊的变量类型export位置参数shift 2、引用&#xff08;1&#xff09;引用变量&#xff08;2&#xff09;转义 3、条件判断&#xff08;1&#xff09;条件测试结构&#xff08…...

GD32 MCU是如何进入中断函数的

用过GD32 MCU的小伙伴们都知道&#xff0c;程序是顺序执行的&#xff0c;但当有中断来的时候程序会跳转到中断函数&#xff0c;执行完中断函数后程序又继续回到原来的位置继续执行&#xff0c;那么你们知道MCU是如何找到中断函数入口的吗&#xff1f; 今天我们就以GD32F303系列…...

Ruby 循环

Ruby 循环 在编程中&#xff0c;循环是一种常用的控制结构&#xff0c;它允许我们重复执行一段代码多次。Ruby 作为一种灵活的编程语言&#xff0c;提供了多种循环方法&#xff0c;包括 while、until、for、each 和 loop 等。本文将详细介绍 Ruby 中的循环机制&#xff0c;并通…...

三字棋游戏(C语言详细解释)

hello&#xff0c;小伙伴们大家好&#xff0c;算是失踪人口回归了哈&#xff0c;主要原因是期末考试完学校组织实训&#xff0c;做了俄罗斯方块&#xff0c;后续也会更新&#xff0c;不过今天先从简单的三字棋说起 话不多说&#xff0c;开始今天的内容 一、大体思路 我们都知…...

H3CNE(计算机网络的概述)

1. 计算机网络的概述 1.1 计算机网络的三大基本功能 1. 资源共享 2. 分布式处理与负载均衡 3. 综合信息服务 1.2 计算机网络的三大基本类型 1.3 网络拓扑 定义&#xff1a; 网络设备连接排列的方式 网络拓扑的类型&#xff1a; 总线型拓扑&#xff1a; 所有的设备共享一…...

【极客日常】Golang一个的slice数据替换的bug排查

上周某天下班前&#xff0c;接到同事转来一个bug要排查&#xff0c;症状是代码重构之后某些业务效果不符合预期&#xff0c;由于代码重构人是笔者&#xff0c;于是blame到笔者这边。经过10min左右的排查和尝试后&#xff0c;解决了这个问题&#xff1a;既往逻辑没有改动&#x…...

HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号3

基础认证题库请移步&#xff1a;HarmonyOS应用开发者基础认证题库 注&#xff1a;有读者反馈&#xff0c;题库的代码块比较多&#xff0c;打开文章时会卡死。所以笔者将题库拆分&#xff0c;单选题20个为一组&#xff0c;多选题10个为一组&#xff0c;题库目录如下&#xff0c;…...

UE4-光照重建

当我们拉入新的光源和模型到我们的场景中后&#xff0c;会产生这样的情况&#xff1a; Preview:预览 表示此时由于光照物体所产生的阴影都是预览级别的并不是真正的效果。 方法一&#xff1a; 或者也可以在世界大纲中选中我们的光源&#xff0c;然后将我们的光源改变为可以…...

【2024德国签证】留学面签问题汇总

在去交材料的时候&#xff0c;可能会被随机安排面试。这些面试问题一般都很简单&#xff0c;主要是测试你的基本英文交流能力。无需担心&#xff0c;签证官不会问太专业的问题&#xff0c;因为他们也不懂专业内容。到目前为止&#xff0c;没有一个博士生因为这个面试被拒签。毕…...

知识点大纲

学习方法 学习、整理笔记过程中&#xff0c;顺便整理出一个以问题为模版的大纲&#xff0c;到时候对着问题&#xff0c;就像是在和面试官讲解那样&#xff0c;相当于升级版的费曼学习法 除了看博客&#xff0c;问gpt外&#xff0c;亲自实验也是获取知识及加深印象的关键点 很…...

MySQL:库表操作

MySQL&#xff1a;库表操作 库操作查看创建字符编码集 删除修改备份 表操作创建查看删除修改 库操作 查看 查看存在哪些数据库&#xff1a; show databases;示例&#xff1a; 查看自己当前处于哪一个数据库&#xff1a; select database();示例&#xff1a; 此处由于我不处于任…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...