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

头条网站收录提交入口互联网保险中介平台

头条网站收录提交入口,互联网保险中介平台,成立一个做网站的公司成本,房地产市场最新动态前言 SettingsProvider顾名思义是一个提供设置数据共享的Provider#xff0c;SettingsProvider和Android系统其它Provider有很多不一样的地方#xff0c;如#xff1a; SettingsProvider只接受int、float、string等基本类型的数据#xff1b;SettingsProvider由Android系…前言 SettingsProvider顾名思义是一个提供设置数据共享的ProviderSettingsProvider和Android系统其它Provider有很多不一样的地方如 SettingsProvider只接受int、float、string等基本类型的数据SettingsProvider由Android系统framework进行了封装使用更加快捷方便SettingsProvider的数据由键值对组成 SettingsProvider有点类似Android的properties系统Android属性系统SystemProperties。SystemProperties除具有SettingsProvider以上的三个特性SettingsProvider和SystemProperties的不同点在于 数据保存方式不同SystemProperties的数据保存属性文件中/system/build.prop等开机后会被加载到system properties storeSettingsProvider的数据保存在文件/data/system/users/0/settings_***.xml和数据库settings.db中作用范围不同SystemProperties可以实现跨进程、跨层次调用即底层的c/c可以调用java层也可以调用SettingProvider只能能在java层APP使用公开程度不同SettingProvider有部分功能上层第三方APP可以使用SystemProperties上层第三方APP不可以使用。 用一句话概括SettingsProvider的作用SettingsProvider包含全局性、系统级别的用户编好设置。在手机中有一个Settings应用用户可以在Settings里面做很多设备的设置这些用户偏好的设置很多就保存在SettingsProvider中。例如飞行模式。 在Android 6.0版本时SettingsProvider被重构Android从性能、安全等方面考虑把SettingsProvider中原本保存在settings.db中的数据目前全部保存在XML文件中。 SettingsProvider概览 主要源码 SettingsProvider的代码数量不多主要包含如下的java文件 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java frameworks/base/core/java/android/provider/Settings.java 数据分类 SettingsProvider对数据进行了分类分别是Global、System、Secure三种类型它们的区别如下 Global所有的偏好设置对系统的所有用户公开第三方APP有读没有写的权限System包含各种各样的用户偏好系统设置Secure安全性的用户偏好系统设置第三方APP有读没有写的权限。 AndroidManifest.xml配置 SettingsProvider的AndroidManifest.xml文件对应用和ContentProvider的配置如下 manifest ......android:sharedUserIdandroid.uid.systemapplication android:allowClearUserDatafalseandroid:labelstring/app_labelandroid:processsystem......android:directBootAwaretrueprovider android:nameSettingsProviderandroid:authoritiessettingsandroid:multiprocessfalseandroid:exportedtrueandroid:singleUsertrueandroid:initOrder100 //application /manifest这些代码定义在文件frameworks/base/packages/SettingsProvider/AndroidManifest.xml中。 上面的Manifest配置由sharedUserId可知SettingsProvider运行在系统进程中定义的ContentProvider实现类是SettingsProviderUri凭证是settings。 SettingsProvider的启动过程 启动SettingsProvider即运行SettingsProvider和打开一个Activity类似会回调ContentProvider的生命周期方法首先的会调用OnCreate()方法如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 public boolean onCreate() {synchronized (mLock) {......mHandlerThread new HandlerThread(LOG_TAG,Process.THREAD_PRIORITY_BACKGROUND);mHandlerThread.start();mSettingsRegistry new SettingsRegistry();}registerBroadcastReceivers();startWatchingUserRestrictionChanges();return true; }上面的代码首先是实例化一个HandlerThread的实例mHandlerThread优先级为Process.THREAD_PRIORITY_BACKGROUND下文会用到。然后实例化SettingsRegistry的实例mSettingsRegistry这一步很重要。接着会注册广播接收器所关心的广播包括设备用户变化以及APP卸载的广播设备用户的变化对大多数地方使用SettingProvider的影响不是很大本文就不再阐述和用户变化相关的内容了。但是APP卸载这里需要关注一下当一个APP有数据保存在SettingsProvider时APP被卸载后被卸载的APP设置的所有数据都会被清除。回到SettingsRegistry的实例化过程构造方法如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 final class SettingsRegistry {private static final String DROPBOX_TAG_USERLOG restricted_profile_ssaid;private static final String SETTINGS_FILE_GLOBAL settings_global.xml;private static final String SETTINGS_FILE_SYSTEM settings_system.xml;private static final String SETTINGS_FILE_SECURE settings_secure.xml;private static final String SETTINGS_FILE_SSAID settings_ssaid.xml;private static final String SETTINGS_FILE_CONFIG settings_config.xml;public SettingsRegistry() {.....migrateAllLegacySettingsIfNeeded();}migrateAllLegacySettingsIfNeeded()方法从命名上是迁移settings数据迁移什么数据呢从哪里迁移到哪里呢继续往下看 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 private void migrateAllLegacySettingsIfNeeded() {synchronized (mLock) {final int key makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);File globalFile getSettingsFile(key);if (globalFile.exists()) {return;}......DatabaseHelper dbHelper new DatabaseHelper(getContext(), userId);SQLiteDatabase database dbHelper.getWritableDatabase();migrateLegacySettingsForUserLocked(dbHelper, database, userId);// Upgrade to the latest version.UpgradeController upgrader new UpgradeController(userId);upgrader.upgradeIfNeededLocked();......} }上面的代码首先是调用了makeKey()方法所谓makeKey()就是和上文中的数据分类小章节中提到的System、Global和Secure三种key。然后调用getSettingsFile()方法获取到一个File对象的实例如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 private File getSettingsFile(int key) {if (isGlobalSettingsKey(key)) {final int userId getUserIdFromKey(key);return new File(Environment.getUserSystemDirectory(userId),SETTINGS_FILE_GLOBAL);} else if (isSystemSettingsKey(key)) {final int userId getUserIdFromKey(key);return new File(Environment.getUserSystemDirectory(userId),SETTINGS_FILE_SYSTEM);} else if (isSecureSettingsKey(key)) {final int userId getUserIdFromKey(key);return new File(Environment.getUserSystemDirectory(userId),SETTINGS_FILE_SECURE);} else {throw new IllegalArgumentException(Invalid settings key: key);} }上面的代码中对Global、System、Secure分别生成一个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()方法实例化一个DatabaseHelperDatabaseHelper是SQLiteOpenHelper的子类然后调用getWritableDatabase()获取到指向数据库文件的SQLiteDatabase实例database。从Android SQLite的架构可知这个过程会调用SQLiteOpenHelper的onCreate()方法如果读者对这个过程迷惑的可以阅读Android的API指南Android SQLite API 指南。 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java中。 public void onCreate(SQLiteDatabase db) {db.execSQL(CREATE TABLE system ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE ON CONFLICT REPLACE, value TEXT ););db.execSQL(CREATE INDEX systemIndex1 ON system (name););createSecureTable(db);// Only create the global table for the singleton owner/system userif (mUserHandle UserHandle.USER_SYSTEM) {createGlobalTable(db);}......// Load initial volume levels into DBloadVolumeLevels(db);// Load inital settings valuesloadSettings(db); }这个方法调用db.execSQL(CREATE TABLE system …、createSecureTable()、createGlobalTable()分别创建System、Secure、Global三个数据库表这个和上文中数据分类章节中的内容一致。接着调用loadVolumeLevels(db)方法把默认的铃声音量、音乐音量、通知音量以及震动设置等等写入到数据库的System表格中。处理完后调用方法loadSettings(db)如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java中。 private void loadSettings(SQLiteDatabase db) {loadSystemSettings(db);loadSecureSettings(db);// The global table only exists for the owner/system userif (mUserHandle UserHandle.USER_SYSTEM) {loadGlobalSettings(db); }loadSettings()这个方法和loadVolumeLevels()方法类似都是加载很多默认值写入到数据库中这些默认值很大一部分被定义在文件frameworks/base/packages/SettingsProvider/res/values/defaults.xml中也有一些来自其它地方。总之loadVolumeLevels()和loadSettings()的作用就是在手机第一次启动时把手机编好设置的默认值写入到数据库settings.db中。 DatabaseHelper的onCreate()方法执行完毕后这里又回到migrateAllLegacySettingsIfNeeded()方法中DatabaseHelper创建完毕后继续调用migrateLegacySettingsForUserLocked()方法如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,SQLiteDatabase database, int userId) {// Move over the system settings.final int systemKey makeKey(SETTINGS_TYPE_SYSTEM, userId);ensureSettingsStateLocked(systemKey);SettingsState systemSettings mSettingsStates.get(systemKey);migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);systemSettings.persistSyncLocked();......// Drop the database as now all is moved and persisted.if (DROP_DATABASE_ON_MIGRATION) {dbHelper.dropDatabase();} else {dbHelper.backupDatabase();} }上面的代码中的每个方法都是那么重要首先是ensureSettingsStateLocked(systemKey)如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 private void ensureSettingsStateLocked(int key) {if (mSettingsStates.get(key) null) {......SettingsState settingsState new SettingsState(mLock, getSettingsFile(key), key,maxBytesPerPackage, mHandlerThread.getLooper());mSettingsStates.put(key, settingsState);} }上面代码实例化一个SettingsState对象这个对象指向文件/data/system/users/0/settings_system.xml然后把settingsState放置在对象mSettingsStates中。回到migrateLegacySettingsForUserLocked()方法ensureSettingsStateLocked()执行完毕后调用migrateLegacySettingsLocked()方法如下 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 private void migrateLegacySettingsLocked(SettingsState settingsState,SQLiteDatabase database, String table) {SQLiteQueryBuilder queryBuilder new SQLiteQueryBuilder();queryBuilder.setTables(table);Cursor cursor queryBuilder.query(database, ALL_COLUMNS,null, null, null, null, null);try {......while (!cursor.isAfterLast()) {String name cursor.getString(nameColumnIdx);String value cursor.getString(valueColumnIdx);settingsState.insertSettingLocked(name, value,SettingsState.SYSTEM_PACKAGE_NAME);cursor.moveToNext();}} finally {cursor.close();} }上面这个方法查询数据库中System所有的设置然后在while循环中把每个值的信息作为insertSettingLocked()的参数insertSettingLocked()方法如下 public boolean insertSettingLocked(String name, String value, String packageName) {Setting oldState mSettings.get(name);String oldValue (oldState ! null) ? oldState.value : null;if (oldState ! null) {......} else {Setting state new Setting(name, value, packageName);mSettings.put(name, state);}...... }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java中。 上面的方法把每个设置项封装到对象Setting中接着有把state放置到ArrayMapString, Setting的实例mSettings中。 那么从方法ensureSettingsStateLocked()到insertSettingLocked()方法这个过程表明有一个对象SettingsState指向文件/data/system/users/0/settings_system.xml持有变量mSettings而mSettings持有封装了设置项的name, value, packageName的对象Setting换句话说settings_system.xml文件中的所有的设置项间接被SettingsState持有。 又回到migrateLegacySettingsForUserLocked()方法migrateLegacySettingsLocked()方法执行完毕后调用systemSettings.persistSyncLocked()systemSettings是SettingsState的实例代表的是settings_system.xml所有的设置项persistSyncLocked()方法就是把systemSettings持有的所有的设置项从内存中固化到文件settings_system.xml中这个过程的代码就不贴出来了。migrateLegacySettingsForUserLocked()方法中省略的代码就是和上文的这几个方法一样把settings_global.xml、settings_secure.xml两个文件中的所有设置项封装到Setting中被SettingsState持有。 也就是说settings_global.xml、settings_secure.xml、settings_system.xml三个文件的所有设置项间接被SettingsState持有而SettingsState又被封装到类SettingsProvider.java的变量mSettingsStates中mSettingsStates是SparseArray的实例。它们的层次关系如下图 再次回到方法migrateLegacySettingsForUserLocked()在把数据中的数据转移到xml文件后执行下面这段代码 // Drop the database as now all is moved and persisted. if (DROP_DATABASE_ON_MIGRATION) {dbHelper.dropDatabase(); } else {dbHelper.backupDatabase(); }如果是工程版本的系统把数据库settings.db重命名为settings.db-backup如果是非工程版本的系统把数据库文件删除也会删除日志settings.db-journal。 SettnigsProvider启动时会创建settings.db数据库然后把所有的默认设置项写入到数据库接着会把数据库中所有的设置项从数据库转移到xml文件中随后便会对数据库执行删除操作。为什么会有这么一个过程这些过程是否可以移除创建数据库这一步其实这个过程是为了兼容之前的版本而设计在SettingsProvider被Android重构后SettingsProvider中数据库相关的代码Android已经停止更新。 封装SettingsProvider接口 由章节前言中的描述SettingsProvider是向整个Android系统提供用户编好设置的提供程序所保存的数据类型和方式上也有一定约束和规定且要求使用SettingsProvider是方便的代码量少的。因此需要对ContentProvider的一些接口进行封装以保证在整个Android的java层任何一个地方都能方便、快捷的使用SettingsProvider进行数据查询数据更新和数据插入。所以理所当然地framework有一个类Settings.java对使用SettingsProvider进行了封装。如下 public final class Settings {public static final String AUTHORITY settings;public static final class Global extends NameValueTable {public static final Uri CONTENT_URI Uri.parse(content:// AUTHORITY /global);......}public static final class Secure extends NameValueTable {public static final Uri CONTENT_URI Uri.parse(content:// AUTHORITY /secure);......}public static final class System extends NameValueTable {public static final Uri CONTENT_URI Uri.parse(content:// AUTHORITY /system);......}private static class NameValueCache {private final Uri mUri;private final HashMapString, String mValues new HashMapString, String();public String getStringForUser(ContentResolver cr, String name, final int userHandle) {......}public boolean putStringForUser(ContentResolver cr, String name, String value,final int userHandle) {......}private IContentProvider lazyGetProvider(ContentResolver cr) {IContentProvider cp null;synchronized (NameValueCache.this) {cp mContentProvider;if (cp null) {cp mContentProvider cr.acquireProvider(mUri.getAuthority());}}return cp;} }这个类定义在文件frameworks/base/core/java/android/provider/Settings.java中。 上面的代码中分别声明了Global、Secure、System三个静态内部类分别对应SettingsProvider中的Global、Secure、System三种数据类型。Global、Secure、System三个静态内部类会分别持有自己NameValueCache的实例变量每个NameValueCache持有指向SettingsProvider中的SettingsProvider.java的AIDL远程调用IContentProvider读者可以阅读《Android System Server大纲之ContentService和ContentProvider原理剖析》了解ConatentProvider的这个过程。因此查询数据需要经过NameValueCache的getStringForUser()方法插入数据需要经过putStringForUser()方法。同时NameValueCache还持有一个变量mValues用于保存查询过的设置项以便下下次再次发起查询时能够快速返回。 操作SettingsProvider 由于Settings.java对使用SettingsProvider进行了封装所以使用起来相当简单简洁。由于Global、Secure、System三种数据类型的使用是几乎相同所以本文就只以Global为例对查询插入数据的过程进行分析。 查询数据 从SettingsProvider的Global中查询数据查询是否是飞行模式使用方法如下 String globalValue Settings.Global.getString(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON); 上面的代码用起来代码量很少只需要一行代码即可查询到所需要的值。深入Settings.java看getString()方法 public static String getString(ContentResolver resolver, String name) {return getStringForUser(resolver, name, UserHandle.myUserId()); }/** hide */ public static String getStringForUser(ContentResolver resolver, String name,int userHandle) {if (MOVED_TO_SECURE.contains(name)) {Log.w(TAG, Setting name has moved from android.provider.Settings.Global to android.provider.Settings.Secure, returning read-only value.);return Secure.getStringForUser(resolver, name, userHandle);}return sNameValueCache.getStringForUser(resolver, name, userHandle); }这些方法定义在文件frameworks/base/core/java/android/provider/Settings.java中。 getString()直接调用了getStringForUser()getStringForUser()首先有做一个判断MOVED_TO_SECURE.contains(name)做这个判断是因为在Android系统的更新中保存在Global、Secure、System三种类型的数据的存放位置有变化所以需要加这个判断兼容老版本的使用方法。在章节“封装SettingsProvider接口”中提到查询必须经过NameValueCache.getStringForUser()方法如下 public String getStringForUser(ContentResolver cr, String name, final int userHandle) {final boolean isSelf (userHandle UserHandle.myUserId());if (isSelf) {......} else if (mValues.containsKey(name)) {return mValues.get(name);......IContentProvider cp lazyGetProvider(cr);// Try the fast path first, not using query(). If this// fails (alternate Settings provider that doesnt support// this interface?) then we fall back to the query/table// interface.if (mCallGetCommand ! null) {try {......Bundle b cp.call(cr.getPackageName(), mCallGetCommand, name, args);if (b ! null) {String value b.getString(Settings.NameValueTable.VALUE);......mValues.put(name, value);}return value;}} catch (RemoteException e) {// Not supported by the remote side? Fall through// to query().}}Cursor c null;try {c cp.query(cr.getPackageName(), mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,new String[]{name}, null, null);String value c.moveToNext() ? c.getString(0) : null;synchronized (NameValueCache.this) {mValues.put(name, value);}return value;......if (c ! null) c.close();} } }这个方法定义在文件frameworks/base/core/java/android/provider/Settings.java中。 首先从缓存mValues变量中去找如果没有查询到就调用SettingsProvider的call()接口如果call()接口也没有查询到再调用query()接口。这里用的是call()接口下文就以call()接口往下分析。cp.call()会调用到SettingsProvider的call()方法读者可以阅读《Android System Server大纲之ContentService和ContentProvider原理剖析》了解ConatentProvider的这个过程。注意参数mCallGetCommand。 public Bundle call(String method, String name, Bundle args) {final int requestingUserId getRequestingUserId(args);switch (method) {case Settings.CALL_METHOD_GET_GLOBAL: {Setting setting getGlobalSetting(name);return packageValueForCallResult(setting, isTrackingGeneration(args));}case Settings.CALL_METHOD_GET_SECURE: {Setting setting getSecureSetting(name, requestingUserId);return packageValueForCallResult(setting, isTrackingGeneration(args));}......}return null; }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 上层传过来的参数的command是mCallGetCommand即Settings.CALL_METHOD_GET_GLOBAL所以调用getGlobalSetting()方法在章节“SettingsProvider的启动过程”中可知getGlobalSetting()返回的Setting setting是封装了设置项name、value等信息的查看getGlobalSetting()方法 private Setting getGlobalSetting(String name) {// Get the value.synchronized (mLock) {return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_GLOBAL,UserHandle.USER_SYSTEM, name);} }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 通过mSettingsRegistry.getSettingLocked()继续寻找 public Setting getSettingLocked(int type, int userId, String name) {final int key makeKey(type, userId);SettingsState settingsState peekSettingsStateLocked(key);return settingsState.getSettingLocked(name); }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 通过peekSettingsStateLocked(key)寻找SettingsState private SettingsState peekSettingsStateLocked(int key) {SettingsState settingsState mSettingsStates.get(key);if (settingsState ! null) {return settingsState;}ensureSettingsForUserLocked(getUserIdFromKey(key));return mSettingsStates.get(key); }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 获取到SettingsState settingsState回到getSettingLocked()调用settingsState.getSettingLocked(name) public Setting getSettingLocked(String name) {if (TextUtils.isEmpty(name)) {return mNullSetting;}Setting setting mSettings.get(name);if (setting ! null) {return new Setting(setting);}return mNullSetting; }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java中。 到getSettingLocked()最终获取到Setting setting其实这个过程就是章节“SettingsProvider的启动过程”中的层次关系图的反映读者可以查看这个图更好理解这个过程。 插入数据 从SettingsProvider的Global中插入数据插入飞行模式的使用方法如下 boolean isSuccess Settings.System.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); 和查询一样代码非常简洁这个过程和查询几乎类似将快速游览这个过程。往下跟踪 public static boolean putInt(ContentResolver cr, String name, int value) {return putString(cr, name, Integer.toString(value)); } public static boolean putString(ContentResolver resolver,String name, String value) {return putStringForUser(resolver, name, value, UserHandle.myUserId()); } public static boolean putStringForUser(ContentResolver resolver,String name, String value, int userHandle) {......return sNameValueCache.putStringForUser(resolver, name, value, userHandle); }这个方法定义在文件frameworks/base/core/java/android/provider/Settings.java中。 和查询一样继续看putStringForUser() public boolean putStringForUser(ContentResolver cr, String name, String value,final int userHandle) {try {Bundle arg new Bundle();arg.putString(Settings.NameValueTable.VALUE, value);arg.putInt(CALL_METHOD_USER_KEY, userHandle);IContentProvider cp lazyGetProvider(cr);cp.call(cr.getPackageName(), mCallSetCommand, name, arg);} catch (RemoteException e) {Log.w(TAG, Cant set key name in mUri, e);return false;}return true; }这个方法定义在文件frameworks/base/core/java/android/provider/Settings.java中。 直接调用SettingsProvider的call()接口 public Bundle call(String method, String name, Bundle args) {final int requestingUserId getRequestingUserId(args);switch (method) {......case Settings.CALL_METHOD_PUT_GLOBAL: {String value getSettingValue(args);insertGlobalSetting(name, value, requestingUserId, false);break;}case Settings.CALL_METHOD_PUT_SECURE: {String value getSettingValue(args);insertSecureSetting(name, value, requestingUserId, false);break;}......}return null; }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 首先调用getSettingValue(args)获取对应的设置项接着insertGlobalSetting()方法 private boolean insertGlobalSetting(String name, String value, int requestingUserId,boolean forceNotify) {return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT,forceNotify); }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 直接调用了mutateGlobalSetting()方法 private boolean mutateGlobalSetting(String name, String value, int requestingUserId,int operation, boolean forceNotify) {// Make sure the caller can change the settings - treated as secure.enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);// If this is a setting that is currently restricted for this user, do not allow// unrestricting changes.if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {return false;}// Perform the mutation.synchronized (mLock) {switch (operation) {case MUTATION_OPERATION_INSERT: {return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM,name, value, getCallingPackage(), forceNotify);}......}}return false; }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 首先对使用的进行权限检查然后调用mSettingsRegistry.insertSettingLocked()方法 public boolean insertSettingLocked(int type, int userId, String name, String value,String packageName, boolean forceNotify) {final int key makeKey(type, userId);SettingsState settingsState peekSettingsStateLocked(key);final boolean success settingsState.insertSettingLocked(name, value, packageName);if (forceNotify || success) {notifyForSettingsChange(key, name);}return success; }这个方法定义在文件frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中。 到这里就不往下分析了其实这个即是查询的反过程结合章节“SettingsProvider的启动过程”中的层次关系图能够很好理解这个过程。 第三方APP使用SettingsProvider 第三方APP可以通过framework的Settings.java查询SettingsProvider中的设置项使用方法查阅章节“查询数据”。第三APP是否可以修改SettingsProvider的设置项Android系统不允许第三方APP修改SettingsProvider中的设置项。 权限问题 查阅SettingsProvider的设置项不需要声明任何权限。 修改SettingsProvider需要权限 android.permission.WRITE_SETTINGSProtection level: signature Secure数据android.permission.WRITE_SECURE_SETTINGSNot for use by third-party applications. 对已Global和Secure模块还需要关心上文中的isGlobalOrSecureSettingRestrictedForUser()方法设置到的限制。 总结 本文从SettingsProvider的启动过程到使用SettingsProvider查询插入数据进行了详细的过程描述在SettingsProvider的启动过程中需要创建数据库把默认设置项值写入到数据库把数据中的所有数据迁移到xml文件中。SettingsProvider的查询和插入结合章节“SettingsProvider的启动过程”中的层次关系图一目了然。对于第三方APP只有读没有写的能力。由于SettingsProvider的特性虽然SettingsProvider是跨进程通信但是由于从多个层次都做了缓存且SettingsProvider中的同步协作机制只要时间都是花费在Binder通信上面但是Binder通信是一种快速的跨进程通信的过程所以在主线程UI线程中可以直接使用SettingsProvider查阅插入数据而不会导致UI阻塞导致ANR应用程序无响应。另外由于SettingsProvider的特性和限制SettingsProvider不予写入过多的数据最好只是系统设置相关的设置项才保存到SettingsProvider中同时也不适合写入过大的数据否则将会严重影响SettingsProvider的性能。 原作者FamilyYuan 链接https://www.jianshu.com/p/d48977f220ee
http://www.hkea.cn/news/14290792/

相关文章:

  • 四川省建设厅申报网站南宁模板建站
  • 成都网站seo诊断石材企业网站源码
  • 百度云注册域名可以做网站明码玉环哪里有做网站
  • 汽车o2o网站建设国外代理ip地址 免费
  • 南宁企业网站建设制作如何熟悉网站项目的逻辑
  • dede搭建网站教程supercell账号注册网站
  • 在新西兰做兼职的网站网络营销专业好不好
  • dedecms 门户网站查看wordpress密码破解
  • 做运营的网站网易企业邮箱pop3设置
  • 阿里巴巴网站首页怎么制作广告标识标牌制作公司
  • 张家港建网站公司linux 网站备份
  • 商城网站有什么好处wordpress添加侧栏
  • 加网络网站建设工作室网站建设 app
  • 整站外包优化公司设计网站的公司
  • 化工网站建站模板可以做试题的网站
  • discuz建站流程他达拉非的副作用和危害
  • 手机网站设计公司立找亿企邦网站建设中iis
  • 保定高端网站建设套路网站怎么做的
  • 中国最大的家装网站使用下载的整站asp源代码建设自己的私人网站需要注意哪些
  • 长沙企业建站销售电话合肥房产网新楼盘二手房
  • 三水住房和城乡建设局的网站南山网站建设找哪家公司好
  • 公司网站地图怎么做wordpress评论验证码
  • 专业网站建设定制公司哪家好wordpress手机号
  • 大连建设工程信息网站超星毕业设计平台
  • 网站备案拍照是什么泉州网站制作哪个好薇
  • 西宁做网站最好的公司哪家好开发app软件需要多少钱
  • 网站+建设+拖拉+源码+系统建筑工人招工网
  • 网站建设硬件设置外贸网站开发推广
  • 龙岗网站建设要多少钱做网站的公司怎么推销
  • 2016年做网站能赚钱吗网站建站实训总结