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

我们有些需求需要修改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.csdn.net/qq_34149526/article/details/83307695

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值