做Android终端我们总会遇到跨应用通信的,比较采用Broadcast、AIDL等方式进行实时数据更新,或者采用文件共享的方式进行配置保存。在做配置保存的时候Android提供了一个Settings配置来让我们进行跨进程数据互通,但是该种方式只适合Android6.0以下的做法,Android6.0及以上会报一个异常,不得不让我们采用其他的形式去进行配置共享。
Android系统提供一个数据共享的系统组件ContentProvider,我们可以采用该种方式进行模仿系统的Settings,从而达到不管Android版本多少都能使用,使用该类,首先我们需要在AndroidManifest.xml中配置我们的Provider:
我们需要去手造一个SettingsProvider类,该类具体实现如下:
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* @Description: 数据共享
* @Encode: UTF-8
* Created by zzj on 2018/6/5.
*/
public class SettingsProvider extends ContentProvider {
private final String DATABASE_NAME = "_zzj_settings.db";
private final String TABLE_NAME = "my_settings";
private SettingsHelper helper;
private SQLiteDatabase db;
@Override
public boolean onCreate() {
helper = new SettingsHelper(getContext(), DATABASE_NAME, null, 1);
db = helper.getReadableDatabase();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return db.query(TABLE_NAME, projection, selection, selectionArgs, null, sortOrder, null);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
synchronized (SettingsProvider.class) {
db.insert(TABLE_NAME, null, values);
}
return null;
}
private boolean hasElement(String table, String key) {
synchronized (SettingsProvider.this) {
boolean isRepeat = false;
Cursor cursor = null;
try {
cursor = db.rawQuery("select * from " + table + " where key = ?", new String[]{key});
if (cursor != null && cursor.getCount() > 0) {
isRepeat = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return isRepeat;
}
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
db.delete(TABLE_NAME, selection, selectionArgs);
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values,
@Nullable String selection, @Nullable String[] selectionArgs) {
long id;
synchronized (SettingsProvider.class) {
if (hasElement(TABLE_NAME, selectionArgs[0])) {
Log.d("zzj", "SettingsProvider update() hasElement is true ");
id = db.update(TABLE_NAME, values, selection, selectionArgs);
} else {
Log.d("zzj", "SettingsProvider update() hasElement is false ");
id = db.insert(TABLE_NAME, null, values);
}
}
getContext().getContentResolver().notifyChange(uri, null);
return (int) id;
}
class SettingsHelper extends SQLiteOpenHelper {
private final byte[] LOCK = new byte[0];
private final String TABLE_NAME = "my_settings";
private static final String COLUMN_KEY = "key";
private static final String COLUMN_INT_VALUE = "intValue";
private static final String COLUMN_STRING_VALUE = "stringValue";
private final String SQL_CREATE_TABLE = "create table if not exists " +
"my_settings(id integer primary key autoincrement," +
"key text not null unique,intValue integer,stringValue text)";
public SettingsHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
我们需要去继承ContentProvider然后自己手动去实现一个SQLiteOpenHelper,创建属于我们的数据库表,这里我只做了两个简单的字段,一个是整形int的intValue,一个是文本型text的stringValue,能满足我们大部分的需求,如果自己需要更多的功能,自己可在这基础上继续适量往上加字段。
写完ContentProvider后我们需要提供一个Util工具类供其他应用使用,这样就免去了其他应用手动去读写这个数据库了。
SettingsUtil.java
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
/**
* @Description: settings ContentProvider
* @Encode: UTF-8
* Created by zzj on 2018/6/6.
*/
public class SettingsUtil {
public static final String URI_CONTENT = "content://com.zzj.provider";
public static final String COLUMN_KEY = "key";
public static final String COLUMN_INT_VALUE = "intValue";
public static final String COLUMN_String_VALUE = "stringValue";
/**
* update int value
*
* @param context
* @param key KEY
*/
public static void putInt(Context context, String key, int value) {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(COLUMN_KEY, key);
values.put(COLUMN_INT_VALUE, value);
resolver.update(Uri.parse(URI_CONTENT), values, COLUMN_KEY + " = ?", new String[]{key});
}
/**
* update String value
* @param context
* @param key
* @param value
*/
public static void putString(Context context, String key, String value) {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(COLUMN_KEY, key);
values.put(COLUMN_String_VALUE, value);
resolver.update(Uri.parse(URI_CONTENT), values, COLUMN_KEY + " = ?", new String[]{key});
}
/**
* get int value by key
*
* @param context
* @param key
* @param defaultValue
* @return
*/
public static int getInt(Context context, String key, int defaultValue) {
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(Uri.parse(URI_CONTENT), null, COLUMN_KEY + " = ?", new String[]{key}, null);
if (cursor == null) {
return defaultValue;
}
if (cursor.getCount() <= 0){
cursor.close();
return defaultValue;
}
cursor.moveToFirst();
int value = cursor.getInt(2);
cursor.close();
return value;
}
/**
* get String value by key
* @param context
* @param key
* @param defaultValue
* @return
*/
public static String getString(Context context,String key,String defaultValue){
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(Uri.parse(URI_CONTENT), null, COLUMN_KEY + " = ?", new String[]{key}, null);
if (cursor == null) {
return defaultValue;
}
if (cursor.getCount() <= 0){
cursor.close();
return defaultValue;
}
cursor.moveToFirst();
String value = cursor.getString(3);
cursor.close();
return value;
}
/**
* 自行定义的Key值,根据应用自行商量
*/
public final class KEY {
/**
* 测试Key
*/
public final static String TEST = "test";
}
}
我们可以看到SettingsUtil里面提供了获取整形和String类型的值,也提供一个写入int和String的方法,如果需要更加丰富的功能,可自己往里面添加,写完Util后我们就可以将这个类共享给其他应用使用了,需要特别注意的一点就是提供数据共享的那个应用要注册Provider,不然数据共享不了。
真正的核心在于ContentProvider的使用,使用该类能轻松的让我们进行IPC通信,有人说使用SharePreference也能达到效果,但SharePreference是非线程安全的,就是说数据的正确性并不能保证,所以还是推荐采用ContentProvider的方式进行。欢迎大家拍砖点赞分享转发~