Setting学习(五)-默认设置值加载及修改

本文深入解析了Android系统中SettingsProvider的工作原理,包括其启动过程、数据迁移、数据分类及默认值设置。SettingsProvider作为数据共享核心组件,负责系统设置的存储与读取,涉及Global、System、Secure三种数据类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们有些需求需要修改setting的默认值来达到目的,这涉及SettingsProvider,(framework/base/packages/SetingsProvider)它主要是做什么的呢,从这个名字也可以看出来,SettingsProvider继承了contentProvider,扮演了数据共享功能的角色,SettingsProvider中有一个数据库,这个数据库是对外开放的,用户在修改系统设置的时候,大部分都是在修改SettngsProvider中的值,当SettingsProvider中的数据发生修改的时候,系统服务会监听到这个修改,然后通过JNI修改一些底层设置,从而修改系统设置和属性。
与Settingsprovider相关的主要有三个文件:
frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
该文件中对状态值进行存储加载,修改Settings数据库的默认值(准确点说是第一次开机后的值)
在这里插入图片描述
/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
定义了开关状态的默认值
在这里插入图片描述
/frameworks/base/core/java/android/provider/Settings.java
定义了各开关状态默认值存储时对应的key
在这里插入图片描述
/data/data/com.android.providers.settings/databases/settings.db
db在数据库中存在的位置
确认是否有默认值
在我们寻找一个设置开关的默认值的时候,我们也要先确认是否有默认值设置,以及是否有状态进行保存(一般保存在settings的db中),判断的条件是:在reboot(重启)之后开关状态仍旧保存或者是在reset(恢复出厂设置)之后开关状态恢复到默认的,才能找到默认值 ,reboot后状态任然保存说明状态储存到了db中,reset后状态恢复的说明有默认值,如WiFi 蓝牙等开关,有默认值,也在db中保存,而像热点开关这种,rerboot后状态没有保存的,一般就是没有默认值的了。
注意:
从代码中的注释我们可以看到
在这里插入图片描述
在Android 6.0版本时,SettingsProvider被重构,Android从性能、安全等方面考虑,把SettingsProvider中原本保存在settings.db中的数据,目前全部保存在XML文件中。

Settingsprovider中对数据也进行了分类,分别是Global、System、Secure三种类型,它们的区别如下:
Global:所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
System:包含各种各样的用户偏好系统设置;
Secure:安全性的用户偏好系统设置,第三方APP有读没有写的权限。
现在来看看SettingsProvider的启动过程
frameworks\base\packages\settingsprovider\src\com\android\providers\settings\SettingsProvider.java
启动SettingsProvider即运行SettingsProvider,和打开一个Activity类似,会回调ContentProvider的生命周期方法,首先的,会调用OnCreate()方法,如下:
在这里插入图片描述
可以看到早onCreate方法中,先实例化了HandlerThread的对象mHandlerThread,优先级是THREAD_PRIORITY_BACKGROUND,然后实例化SettingsRegistry的实例mSettingsRegistry。接下来注册了一个广播接收器,关心的广播包括设备用户变化和app卸载等的广播。现在来看看SettingsRegistry的实例化过程:
在这里插入图片描述
关注里面的migrateAllLegacySettingsIfNeeded方法,他的意思是迁移所有需要的setting数据,但他是怎样迁移的呢,具体看方法内部:
在这里插入图片描述
首先调用了makeKey方法来获得key,这个key就是之前说过的Global、System、Secure三种类型,获得之后通过getSettingsFile方法创建三种类型的File类型实例:
在这里插入图片描述
上面的代码分别生成一个File对象实例,对应的文件为
/data/system/users/0/settings_global.xml
/data/system/users/0/settings_system.xml
/data/system/users/0/settings_secure.xml
那么也就是说,Global类型的数据保存在文件settings_global.xml中,System类型的数据保存在文件settings_system.xml中,Secure类型的数据保存在文件settings_secure.xml中。
继续回到migrateAllLegacySettingsIfNeeded方法,实例化了一个DatabaseHelper,它是SQLiteOpenHelper的子类,然后调用它的getWritableDatabase方法,获得指向数据库文件的SQLiteDatabase的实例database,在DatabaseHelper,要调用生命周期中的onCreate方法:
frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
在这里插入图片描述
在onCreate中通过 db.execSQL("CREATE TABLE system…,createSecureTable(db),createGlobalTable(db)分别创建system,Secure,Global三个数据库表,然后调用loadVolumlevels方法将默认的音乐音量,铃声音量,通知音量,震动设置写到数据库的system的数据表中,然后调用loadSettings方法:
在这里插入图片描述
加载许多默认值写入数据库中,这些默认值很大一部分定义在defaults.xml文件中,loadVolumlevels和loadSettings()的作用就是在手机第一次启动时,把手机编好设置的默认值写入到数据库settings.db中。
然后回到migrateAllLegacySettingsIfNeeded方法,在DatabaseHelper和SQLiteDatabase创建完毕后,调用migrateLegacySettingsForUserLocked方法:
在这里插入图片描述
在migrateLegacySettingsForUserLocked中首先调用了ensureSettingsStateLocked方法
在这里插入图片描述
实例化了settingsState对象指向了sysytem的数据文件,然后将settingsState对象放到mSettingsStates中,然后回到migrateLegacySettingsForUserLocked继续调用migrateLegacySettingsLocked方法
在这里插入图片描述
先查询出所有System的信息,然后在循环中作为insertSettingLocked的参数
在这里插入图片描述
在insertSettingLocked,将每个设置项封装到Setting对象中,再将setting对象方法放进ArrayMap<String, Setting> 对象 mSettings中
可以看到从ensureSettingsStateLocked方法到migrateLegacySettingsLocked方法,首先创建了指向system数据文件(/data/system/users/0/settings_system.xml) 的对象settingsState,它持有变量mSettings,mSettings持有封装了设置项name,vaule,packageName的对象setting,所以settingsState间接拥有了system数据文件/data/system/users/0/settings_system.xml)中的所有设置项
回到migrateLegacySettingsForUserLocked方法,在migrateLegacySettingsLocked方法执行完以后,执行SettingsState的persistSyncLocked方法,它的功能就是将settingsState拥有的设置项从内存中固化到xml文件中。migrateLegacySettingsForUserLocked中省略的几段代码是和上面sysytem数据的操作是一样的,说明最后sysytem,global,secure的设置项都是间接被settingsState拥有
全部执行以后,回到最开始的方法migrateLegacySettingsForUserLocked执行下面几行代码:
在这里插入图片描述
如果是工程版本的系统,把数据库settings.db重命名为settings.db-backup,如果是非工程版本的系统,把数据库文件删除,也会删除日志settings.db-journal。
总结:
在SetttngsProvider的启动过程中,会创建数据库,把默认设置的数据值写入数据库,然后将数据库中的数据全部迁移到xml文件中

由于SetttingsProvider是向整个Android系统提供用户偏好设置的提供程序,在所保存的数据类型和方式上也有一定的规定和约束,为能够保证在整个Android的Java层任意一个地方里面能够方便,快捷的使用SettingsProvider进行数据查询,数据插入,数据更新,所以在framework的provider里面有一个类Settings.java对使用SettingsProvider进行了封装。
frameworks/base/core/java/android/provider/Settings.java
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在settings.java代码创建了三个静态内部类,System,Secure,Global分别对应SettingsProvider中的System,Secure,Global三种数据类型,Global、Secure、System三个静态内部类会分别持有自己NameValueCache的实例变量,每个NameValueCache持有指向SettingsProvider中的SettingsProvider.java的AIDL远程调用IContentProvider,因此,查询数据需要经过NameValueCache的getStringForUser()方法,插入数据需要经过putStringForUser()方法。同时,NameValueCache还持有一个变量mValues,用于保存查询过的设置项,以便下下次再次发起查询时,能够快速返回。
以设备的自动调节亮度为例子:
在Androidmanifest文件中找到display模块
在这里插入图片描述
他的fragment是DisplaySettings
\packages\apps\settings\src\com\android\settings\DisplaySettings.java
在这里插入图片描述
从方法中可以看到他加载的布局是display_settings.cml
在这里插入图片描述
则对应的是自动亮度(auto_brightness)选项 key是auto_brightness
接下来看DisplaySettings的getPreferenceControllers方法
在这里插入图片描述
调用了buildPreferenceControllers方法:
在这里插入图片描述
可以看到AutoBrightnessPreferenceController就是有段自动亮度的controller
来看AutoBrightnessPreferenceController:
packages\apps\settings\src\com\android\settings\display\AutoBrightnessPreferenceController.java
关注updateState和onPreferenceChange这两个方法
在这里插入图片描述
在这里插入图片描述
可以看到自动亮度模式的获取:
在这里插入图片描述
自动亮度模式的设置:
在这里插入图片描述
获取和修改的实质是对SettingsProvider的操作
设备的亮度模式SCREEN_BRIGHTNESS_MODE_AUTOMATIC(自动)和SCREEN_BRIGHTNESS_MODE_MANUAL(手动)都是通过SettingsProvider来操作的,可以看到自动亮度设置属于System系统属性
由于Settings.java对使用SettingsProvider进行了封装,所以,使用起来相当简单简洁
在Settings.java定义了各开关状态默认值存储时对应的key
/frameworks/base/core/java/android/provider/Settings.java
现在深入Settings.java的System内部类里面看看getInt方法:
在这里插入图片描述
可以看到gitInt直接调用了getIntForUser方法:
在这里插入图片描述
在getIntForUser方法中又调用了getStringForUser方法:
在这里插入图片描述
MOVED_TO_SECURE.contains(name)和MOVED_TO_GLOBAL.contains(name)在方法中先进行了
判断,进行判断的原因是在Android系统的更新中,system,secure,globa三种类型的数据的保存的位置有了变化,进行判断是为了兼容老版本的使用方法。最后调用了sNameValueCache.getStringForUser方法,上面也提到过,查询数据的时候必须会经过NameValueCache的getStringForUser()方法
在这里插入图片描述
在这里插入图片描述
从代码中可以看到,先通过mVaules变量中去找,上面也提到过,mVaules会缓存之前查询过的设置项,以便下下次再次发起查询时,能够快速返回,如果没有的话,就会首先尝试快速途径,调用SettingsProvider的call()接口,如果没有查询到的话就调用querry()接口
下面来看call()接口,调用了SettingsProvider的call()方法:
frameworks\base\packages\settingsprovider\src\com\android\providers\settings\SettingsProvider.java
在这里插入图片描述
可以看到,因为上一个方法传来的method是mCallGetCommand,所以走到Settings.CALL_METHOD_GET_SYSTEM,然后调用getSystemSetting方法
在这里插入图片描述
在getSecureSetting里面调用了mSettingsRegistry.getSettingLocked():
在这里插入图片描述
frameworks\base\packages\settingsprovider\src\com\android\providers\settings\SettingsState.java
在这里插入图片描述
最后返回一个封装好的Setting对象,从上面Setttingprivoder的启动流程中可以了解,我们得到的Setting是封装了设置项的name,vaule,packageName等信息的。

数据查询的流程梳理完以后,其实数据的设置putInt()方法的流程和getInt的是类似的
也是先是通过Settings.java然后最后调用到Settingsprovider.java中去.

参考:https://blog.youkuaiyun.com/qq_34149526/article/details/83307695

<think>嗯,用户问的是如何修改默认的settings.gradle配置,使得新建文件时无需加载。首先,我需要确定用户指的是哪个构建工具。常见的构建工具如Gradle(用于Android或Java项目)或者可能是其他项目类型的配置。假设用户指的是Gradle,因为settings.gradle是Gradle项目的一部分。 接下来,用户提到“新建文件无需加载”,这可能意味着他们希望在创建新模块或项目时,避免自动包含某些配置或模块。或者可能是想减少初始化时的加载项,加快项目创建速度。 首先,我需要回忆一下Gradle中settings.gradle的作用。这个文件主要负责项目的模块配置,定义哪些模块属于当前项目。例如,当新建一个模块时,Gradle会自动将其添加到settings.gradle中,这样构建时就会包含该模块。 如果用户希望新建的模块不自动加载,可能需要修改IDE的模板配置,而不是直接修改现有的settings.gradle。例如,在Android Studio中,创建新模块时会自动生成对应的模块并在settings.gradle中添加include语句。要改变这种行为,可能需要自定义项目模板。 或者,用户可能希望默认的settings.gradle不包含某些模块,这样每次新建项目时不需要手动删除这些配置。这时候需要找到Gradle或IDE中生成新项目时的默认模板,并修改其中的settings.gradle模板文件。 另外,也有可能用户误解了settings.gradle的作用,他们可能想要禁用某些插件或配置的自动加载。这时候需要检查Gradle的初始化脚本或项目属性,看看是否有配置可以控制默认加载的模块或插件。 不过,根据常规做法,直接修改settings.gradle的默认配置可能不是最佳实践,因为每个项目可能需要不同的模块。更可能的解决方案是自定义项目创建模板,或者通过脚本在生成项目后自动修改settings.gradle文件。 还有可能用户是在多模块项目中工作,每次新建模块时希望不自动添加到父项目的settings.gradle中,这样他们可以手动控制包含哪些模块。这种情况下,可能需要调整IDE的设置,使其不在创建模块时自动修改settings.gradle,或者使用Gradle的复合构建(composite builds)来分离模块。 总结下来,用户的需求可能是优化项目结构,减少不必要的模块加载,或者加快项目初始化速度。因此,正确的步骤可能是指导用户如何自定义IDE的项目模板,或者在创建新模块后手动调整settings.gradle文件,而不是修改默认配置。同时,需要提醒用户注意这样做可能带来的影响,比如构建系统无法识别模块,导致编译失败等问题。 另外,需要验证是否存在直接修改Gradle默认配置的方法。查阅Gradle文档发现,Gradle本身没有提供全局的settings.gradle模板,每个项目都是独立的。因此,修改默认配置可能需要更改IDE级别的模板文件,例如在Android Studio中,模板存放在安装目录的plugins文件夹下,找到对应的Gradle项目模板,修改其中的settings.gradle内容。 不过,直接修改IDE的模板文件可能会在更新IDE时被覆盖,因此建议用户创建自定义的项目模板,或者在项目生成后编写脚本自动移除不需要的include语句。 最后,整理步骤:首先确认用户的具体需求和环境,然后根据不同的情况提供修改模板、使用脚本或调整IDE设置的方法,同时提醒潜在的风险和注意事项。</think>要修改默认的 `settings.gradle` 配置,使得新建项目或模块时无需加载特定模块或配置,需分情况处理。以下是分步说明: --- ### **1. 理解 `settings.gradle` 的作用** - **功能**:该文件定义项目的模块结构,通过 `include` 语句声明哪些子模块参与构建。 - **默认行为**:使用 IDE(如 Android Studio)新建模块时,会自动在 `settings.gradle` 中添加 `include ':模块名'`。 --- ### **2. 需求场景分析** 若希望新建文件(模块)时 **不自动加载到父项目**,有两种常见场景: 1. **避免自动添加子模块**:新建模块时不自动修改 `settings.gradle`。 2. **全局禁用默认配置**:新建项目时不生成默认模块(如 `app`)。 --- ### **3. 解决方案** #### **场景 1:禁止自动添加子模块到父项目** - **步骤**: 1. **关闭 IDE 的自动配置**: -Android Studio 中:创建新模块时,取消勾选 **"Add to parent project"** 或类似选项。 2. **手动管理 `settings.gradle`**: - 创建模块后,手动删除父项目 `settings.gradle` 中的 `include ':新模块名'` 语句。 #### **场景 2:新建项目时不生成默认模块** - **步骤**: 1. **修改项目模板**: - 找到 IDE 的项目模板文件(如 Android Studio 的模板在安装目录的 `plugins/android/lib/templates` 下)。 - 编辑模板中的 `settings.gradle`,移除默认的 `include ':app'`。 2. **使用自定义脚本**: - 创建项目后,运行脚本自动清理默认配置: ```bash sed -i '/include/d' settings.gradle # 删除所有 include 语句(Linux/macOS) ``` --- ### **4. 注意事项** - **风险**:修改 IDE 模板可能导致版本升级后配置丢失,建议备份。 - **替代方案**:使用 **Gradle 复合构建**(Composite Builds)隔离模块: ```gradle // 在父项目的 settings.gradle 中按需添加模块 if (System.getenv('AUTO_INCLUDE') != 'true') { include ':module1' include ':module2' } ``` --- ### **5. 验证结果** - 新建模块或项目后,检查 `settings.gradle` 是否包含预期内容: ```gradle // 期望:无自动添加的模块 rootProject.name = "MyProject" ``` --- ### **总结** - **直接修改默认配置**:需调整 IDE 模板文件或脚本。 - **推荐做法**:手动管理 `settings.gradle`,结合条件语句控制模块加载,保持灵活性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值