转载请注明出处:http://blog.csdn.net/droyon/article/details/35558783
SettingsProvider采用了双缓冲,我们前面说过SettingsProvider中存在SettingsCache缓冲区,那么在Settings.java中还存在另外一个缓冲区,它就是NameValueCache。
1、
2、
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();
}
}
}
3、public static final class Bookmarks implements BaseColumns{
public static Intent getIntentForShortcut(ContentResolver cr, char shortcut)
//构建shortCut的intent
{
Intent intent = null;
Cursor c = cr.query(CONTENT_URI,
sIntentProjection, sShortcutSelection,
new String[] { String.valueOf((int) shortcut) }, ORDERING);
// Keep trying until we find a valid shortcut
try {
while (intent == null && c.moveToNext()) {
try {
String intentURI = c.getString(c.getColumnIndexOrThrow(INTENT));
intent = Intent.parseUri(intentURI, 0);
} catch (java.net.URISyntaxException e) {
// The stored URL is bad... ignore it.
} catch (IllegalArgumentException e) {
// Column not found
Log.w(TAG, "Intent column not found", e);
}
}
} finally {
if (c != null) c.close();
}
return intent;
}
{
Intent intent = null;
Cursor c = cr.query(CONTENT_URI,
sIntentProjection, sShortcutSelection,
new String[] { String.valueOf((int) shortcut) }, ORDERING);
// Keep trying until we find a valid shortcut
try {
while (intent == null && c.moveToNext()) {
try {
String intentURI = c.getString(c.getColumnIndexOrThrow(INTENT));
intent = Intent.parseUri(intentURI, 0);
} catch (java.net.URISyntaxException e) {
// The stored URL is bad... ignore it.
} catch (IllegalArgumentException e) {
// Column not found
Log.w(TAG, "Intent column not found", e);
}
}
} finally {
if (c != null) c.close();
}
return intent;
}
public static Uri add(ContentResolver cr,
Intent intent,
String title,
String folder,
char shortcut,
int ordering)
{ //加入书签
// If a shortcut is supplied, and it is already defined for
// another bookmark, then remove the old definition.
if (shortcut != 0) {
cr.delete(CONTENT_URI, sShortcutSelection,
new String[] { String.valueOf((int) shortcut) });
}
ContentValues values = new ContentValues();
if (title != null) values.put(TITLE, title);
if (folder != null) values.put(FOLDER, folder);
values.put(INTENT, intent.toUri(0));
if (shortcut != 0) values.put(SHORTCUT, (int) shortcut);
values.put(ORDERING, ordering);
return cr.insert(CONTENT_URI, values);
}
Intent intent,
String title,
String folder,
char shortcut,
int ordering)
{ //加入书签
// If a shortcut is supplied, and it is already defined for
// another bookmark, then remove the old definition.
if (shortcut != 0) {
cr.delete(CONTENT_URI, sShortcutSelection,
new String[] { String.valueOf((int) shortcut) });
}
ContentValues values = new ContentValues();
if (title != null) values.put(TITLE, title);
if (folder != null) values.put(FOLDER, folder);
values.put(INTENT, intent.toUri(0));
if (shortcut != 0) values.put(SHORTCUT, (int) shortcut);
values.put(ORDERING, ordering);
return cr.insert(CONTENT_URI, values);
}
public static CharSequence getTitle(Context context, Cursor cursor) {
//得到title
int titleColumn = cursor.getColumnIndex(TITLE);
int intentColumn = cursor.getColumnIndex(INTENT);
if (titleColumn == -1 || intentColumn == -1) {
throw new IllegalArgumentException(
"The cursor must contain the TITLE and INTENT columns.");
}
String title = cursor.getString(titleColumn);
if (!TextUtils.isEmpty(title)) {
return title;
}
String intentUri = cursor.getString(intentColumn);
if (TextUtils.isEmpty(intentUri)) {
return "";
}
Intent intent;
try {
intent = Intent.parseUri(intentUri, 0);
} catch (URISyntaxException e) {
return "";
}
PackageManager packageManager = context.getPackageManager();
ResolveInfo info = packageManager.resolveActivity(intent, 0);
return info != null ? info.loadLabel(packageManager) : "";
}
}
int titleColumn = cursor.getColumnIndex(TITLE);
int intentColumn = cursor.getColumnIndex(INTENT);
if (titleColumn == -1 || intentColumn == -1) {
throw new IllegalArgumentException(
"The cursor must contain the TITLE and INTENT columns.");
}
String title = cursor.getString(titleColumn);
if (!TextUtils.isEmpty(title)) {
return title;
}
String intentUri = cursor.getString(intentColumn);
if (TextUtils.isEmpty(intentUri)) {
return "";
}
Intent intent;
try {
intent = Intent.parseUri(intentUri, 0);
} catch (URISyntaxException e) {
return "";
}
PackageManager packageManager = context.getPackageManager();
ResolveInfo info = packageManager.resolveActivity(intent, 0);
return info != null ? info.loadLabel(packageManager) : "";
}