转载请注明出处:http://blog.csdn.net/droyon/article/details/35558783
SettingsProvider采用了双缓冲,我们前面说过SettingsProvider中存在SettingsCache缓冲区,那么在Settings.java中还存在另外一个缓冲区,它就是NameValueCache。
NameValueTable用于描述SettingsProvider的数据表,封装了putString方法。 /** * Common base for tables of name/value settings. */ public static class NameValueTable implements BaseColumns { public static final String NAME = "name"; public static final String VALUE = "value"; protected static boolean putString(ContentResolver resolver, Uri uri, String name, String value) { // The database will take care of replacing duplicates. try { ContentValues values = new ContentValues(); values.put(NAME, name); values.put(VALUE, value); resolver.insert(uri, values); return true; } catch (SQLException e) { Log.w(TAG, "Can't set key " + name + " in " + uri, e); return false; } } public static Uri getUriFor(Uri uri, String name) { return Uri.withAppendedPath(uri, name); } }
2.1、封装了lazyGetProvider,根据uri得到相应的ContentProvider,此处为IContentProvider,binder跨进程数据访问。
2.2、封装了getStringForUser方法。此方法分两部分,首先得到long newValuesVersion = SystemProperties.getLong(mVersionSystemProperty, 0);,首先从本地cache中得到想要的数据,如果本地cache中不存在想要的数据,那么进行第二部分,查询数据库。
2.3,如果newVersion不等于目前的version,说明本地的cache和SettingsProvider中的数据存在不同步,需要清空本地cache,重新加载。
// Our own user's settings data uses a client-side cache synchronized (this) { if (mValuesVersion != newValuesVersion) { if (LOCAL_LOGV || false) { Log.v(TAG, "invalidate [" + mUri.getLastPathSegment() + "]: current " + newValuesVersion + " != cached " + mValuesVersion); } mValues.clear(); mValuesVersion = newValuesVersion; } if (mValues.containsKey(name)) { return mValues.get(name); // Could be null, that's OK -- negative caching }
顾名思义 nameValue 的缓冲池。 // Thread-safe. private static class NameValueCache { private final String mVersionSystemProperty; private final Uri mUri; private static final String[] SELECT_VALUE = new String[] { Settings.NameValueTable.VALUE }; private static final String NAME_EQ_PLACEHOLDER = "name=?"; // Must synchronize on 'this' to access mValues and mValuesVersion. private final HashMap<String, String> mValues = new HashMap<String, String>(); private long mValuesVersion = 0; // Initially null; set lazily and held forever. Synchronized on 'this'. private IContentProvider mContentProvider = null; // The method we'll call (or null, to not use) on the provider // for the fast path of retrieving settings. private final String mCallGetCommand; private final String mCallSetCommand; public NameValueCache(String versionSystemProperty, Uri uri, String getCommand, String setCommand) {//传入mCallGetCommand以及mCallSetCommand mVersionSystemProperty = versionSystemProperty; mUri = uri; mCallGetCommand = getCommand; mCallSetCommand = setCommand; } private IContentProvider lazyGetProvider(ContentResolver cr) {//IContentProvider的构造方法 IContentProvider cp = null; synchronized (this) { cp = mContentProvider; if (cp == null) { cp = mContentProvider = cr.acquireProvider(mUri.getAuthority()); } } return cp; } public boolean putStringForUser(ContentResolver cr, String name, String value, final int userHandle) {//putStringForUser 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, "Can't set key " + name + " in " + mUri, e); return false; } return true; } public String getStringForUser(ContentResolver cr, String name, final int userHandle) { final boolean isSelf = (userHandle == UserHandle.myUserId()); if (isSelf) { long newValuesVersion = SystemProperties.getLong(mVersionSystemProperty, 0); // Our own user's settings data uses a client-side cache synchronized (this) { if (mValuesVersion != newValuesVersion) { if (LOCAL_LOGV || false) { Log.v(TAG, "invalidate [" + mUri.getLastPathSegment() + "]: current " + newValuesVersion + " != cached " + mValuesVersion); } mValues.clear(); mValuesVersion = newValuesVersion; } if (mValues.containsKey(name)) { return mValues.get(name); // Could be null, that's OK -- negative caching } } } else { if (LOCAL_LOGV) Log.v(TAG, "get setting for user " + userHandle + " by user " + UserHandle.myUserId() + " so skipping cache"); } IContentProvider cp = lazyGetProvider(cr); // Try the fast path first, not using query(). If this // fails (alternate Settings provider that doesn't support // this interface?) then we fall back to the query/table // interface. if (mCallGetCommand != null) { try { Bundle args = null; if (!isSelf) { args = new Bundle(); args.putInt(CALL_METHOD_USER_KEY, userHandle); } Bundle b = cp.call(cr.getPackageName(), mCallGetCommand, name, args); if (b != null) { String value = b.getPairValue(); // Don't update our cache for reads of other users' data if (isSelf) { synchronized (this) { mValues.put(name, value); } } else { if (LOCAL_LOGV) Log.i(TAG, "call-query of user " + userHandle + " by " + UserHandle.myUserId() + " so not updating cache"); } return value; } // If the response Bundle is null, we fall through // to the query interface below. } 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); if (c == null) { Log.w(TAG, "Can't get key " + name + " from " + mUri); return null; } String value = c.moveToNext() ? c.getString(0) : null; synchronized (this) { mValues.put(name, value); } if (LOCAL_LOGV) { Log.v(TAG, "cache miss [" + mUri.getLastPathSegment() + "]: " + name + " = " + (value == null ? "(null)" : value)); } return value; } catch (RemoteException e) { Log.w(TAG, "Can't get key " + name + " from " + mUri, e); return null; // Return null, but don't cache it. } finally { if (c != null) c.close(); } } }
SettingsProvider之Settings.System(Secure)内部类,布布扣,bubuko.com
SettingsProvider之Settings.System(Secure)内部类
原文地址:http://blog.csdn.net/droyon/article/details/35558783