在Android应用中,我们可以使用以下代码轻易的进行设置值的写入与读取:
boolean result = Settings.Global.putString(this.getContentResolver(), Settings.Global.DEVICE_NAME, "Z97A");
Settings.Global.getString(this.getContentResolver(), Settings.Global.DEVICE_NAME);
该设计在应用中进行调用显得非常优雅,因此在想着仿制framework中android.provider.Settings
以最小量的代码进行相应的实现。
内容提供者实现
package io.cstack.xviewlander;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* 实现内容提供者
*/
public class FoxProvider extends ContentProvider {
public static final String TAG = "FoxProvider";
private Map<String, String> globalDatas;//某一个个表格的数据存放
static final int GLOBAL_ID = 1;//对应的表格ID
static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);//定义一个uri匹配器
uriMatcher.addURI(FoxSettings.AUTHORITY, "global", GLOBAL_ID);//定义与之匹配的uri
}
@Override
public boolean onCreate() {
globalDatas = new HashMap<>();
globalDatas.put(FoxSettings.Global.DEVICE_NAME, "F0X996");//模拟数据加载
return true;
}
/**
* 构造键值返回对象的Cursor
*
* @param name
* @param value
* @return
*/
private MatrixCursor buildParameterCursor(String name, String value) {
String[] columns = new String[]{name};//定义列名
MatrixCursor cursor = new MatrixCursor(columns);
cursor.addRow(new Object[]{value});//定义值
return cursor;
}
/**
* 获取数据对应的查询方法
*
* @param uri
* @param projection
* @param selection
* @param selectionArgs
* @param sortOrder
* @return
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
String key = projection[0];//获取查询的键
String value;
int code = uriMatcher.match(uri);//获取匹配到的表格id
switch (code) {
case GLOBAL_ID:
value = globalDatas.get(key);//从对应表格中获取值
break;
default:
value = null;
break;
}
return buildParameterCursor(key, value);//返回结果
}
/**
* 构建Uri返回MIME类型
*
* @param uri
* @return
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
/**
* global
*/
case GLOBAL_ID:
return "vnd.android.cursor.dir/vnd.foxsettings.global";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
/**
* 设置数据的对应方法
*
* @param uri
* @param values
* @return
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
Log.e(TAG, "insert:" + uri.toString());
int code = uriMatcher.match(uri);
Uri _uri = null;
switch (code) {
case GLOBAL_ID:
String name = null;
for (String key : values.keySet()) {
String value = (String) values.get(key);
globalDatas.put(key, value);
name = key;
_uri = Uri.withAppendedPath(FoxSettings.Global.CONTENT_URI, name);
getContext().getContentResolver().notifyChange(_uri, null);//通知注册数据改变监听
break;
}
break;
default: {
throw new IllegalArgumentException("Bad Uri path:" + uri);
}
}
return _uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
配置清单中注册内容提供者
<provider
android:name="io.cstack.xviewlander.FoxProvider"
android:authorities="foxsettings" />
调用接口实现
package io.cstack.xviewlander;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
/**
* 用于调用的工具接口
*/
public class FoxSettings {
/**
* 定义authorities该值需要需要与AndroidManifest.xml中配置保持一致
*/
public static final String AUTHORITY = "foxsettings";
/**
* 基础的设置查询实现
*/
public static class NameValueTable {
/**
* 设置一个值
*
* @param resolver
* @param uri
* @param name
* @param value
* @return
*/
protected static boolean putString(ContentResolver resolver, Uri uri, String name, String value) {
try {
ContentValues values = new ContentValues();
values.put(name, value);
resolver.insert(uri, values);
return true;
} catch (SQLException e) {
return false;
}
}
/**
* 获取一个值
*
* @param resolver
* @param uri
* @param name
* @param value
* @return
*/
protected static String getString(ContentResolver resolver, Uri uri, String name, String value) {
try {
Cursor query = resolver.query(uri, new String[]{name}, null, new String[]{value}, null);
if (query.moveToFirst()) {
return query.getString(0);
}
return value;
} catch (SQLException e) {
return value;
}
}
public static Uri getUriFor(Uri uri, String name) {
return Uri.withAppendedPath(uri, name);
}
}
/**
* 某一个设置表格实现
*/
public static final class Global extends NameValueTable {
//定义对应表格的Url
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");
//定义可支持设置的KEY常量
public static final String DEVICE_NAME = "device_name";
public static boolean putString(ContentResolver resolver, String name, String value) {
return NameValueTable.putString(resolver, CONTENT_URI, name, value);
}
public static String getString(ContentResolver resolver, String name) {
return NameValueTable.getString(resolver, CONTENT_URI, name, null);
}
public static Uri getUriFor(String name) {
return getUriFor(CONTENT_URI, name);
}
}
}
调用activity实现
public class MainActivity extends Activity {
public static final String TAG = "MainActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getContentResolver().registerContentObserver(FoxSettings.Global.getUriFor(FoxSettings.Global.DEVICE_NAME), true, new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.e(TAG, "selfChange:" + selfChange);
}
});
boolean result = FoxSettings.Global.putString(this.getContentResolver(), FoxSettings.Global.DEVICE_NAME, "F0X007");
String value = FoxSettings.Global.getString(this.getContentResolver(), FoxSettings.Global.DEVICE_NAME);
Log.e("fox", "getString:" + value);
}
}