最近要开发一个跨进程数据共享的功能,要实现这个功能,我脑海里第一个想到的是用SharedPreferences,但是发现在Android 7.0以上的版本Context.MODE_WORLD_READABLE属性已经废除,不能用了,所以放弃使用SharedPreferences来实现了。最终决定使用ContentProvider结合SharedPreferences来实现这个功能,话不多说,上代码
1、在你要进行数据共享的应用程序【A程序】中新建CustomProvider类
package com.hades.toolkit.utils;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Iterator;
/**
* ContentProvider跨进程数据共享
*
* @author Hades
* @date 2021/8/30.
*/
public class CustomProvider extends ContentProvider {
public static final Uri AUTHORITY_URI = Uri.parse("content://com.carshow.provider");//此处可以将com.carshow.provider换成你们自己的包名
public static final Uri CONTENT_URI = AUTHORITY_URI;
public static final String PARAM_KEY = "key";
public static final String PARAM_VALUE = "value";
private final String DB_NAME = "ToolkitProviderData";
private SharedPreferences mStore;
public static Cursor query(Context context, String... keys) {
return context.getContentResolver().query(CONTENT_URI, keys, null, null, null);
}
public static String getString(Context context, String key) {
return getString(context, key, null);
}
public static String getString(Context context, String key, String defValue) {
Cursor cursor = query(context, key);
String ret = defValue;
if (cursor.moveToNext()) {
ret = cursor.getString(0);
if (TextUtils.isEmpty(ret)) {
ret = defValue;
}
}
cursor.close();
return ret;
}
public static int getInt(Context context, String key, int defValue) {
Cursor cursor = query(context, key);
int ret = defValue;
if (cursor.moveToNext()) {
try {
ret = cursor.getInt(0);
} catch (Exception e) {
}
}
cursor.close();
return ret;
}
public static Uri save(Context context, ContentValues values) {
return context.getContentResolver().insert(GlobalProvider.CONTENT_URI, values);
}
public static Uri save(Context context, String key, String value) {
ContentValues values = new ContentValues(1);
values.put(key, value);
return save(context, values);
}
public static Uri save(Context context, String key, int value) {
ContentValues values = new ContentValues(1);
values.put(key, value);
return save(context, values);
}
public static Uri remove(Context context, String key) {
return save(context, key, null);
}
@Override
public boolean onCreate() {
mStore = getContext().getSharedPreferences(DB_NAME, Context.MODE_PRIVATE);
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
int size = projection == null ? 0 : projection.length;
if (size > 0) {
String[] values = new String[size];
for (int i = 0; i < size; i++) {
values[i] = getValue(projection[i], null);
}
return createCursor(projection, values);
}
String key = uri.getQueryParameter(PARAM_KEY);
String value = null;
if (!TextUtils.isEmpty(key)) {
value = getValue(key, null);
}
return createSingleCursor(key, value);
}
protected Cursor createSingleCursor(String key, String value) {
MatrixCursor cursor = new MatrixCursor(new String[]{key}, 1);
if (!TextUtils.isEmpty(value)) {
cursor.addRow(new Object[]{value});
}
return cursor;
}
protected Cursor createCursor(String[] keys, String[] values) {
MatrixCursor cursor = new MatrixCursor(keys, 1);
cursor.addRow(values);
return cursor;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return "";
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
if (values != null && values.size() > 0) {
save(values);
} else {
String key = uri.getQueryParameter(PARAM_KEY);
String value = uri.getQueryParameter(PARAM_VALUE);
if (!TextUtils.isEmpty(key)) {
save(key, value);
}
}
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
String key = selection == null ? selection : uri.getQueryParameter(PARAM_KEY);
if (!TextUtils.isEmpty(key)) {
remove(key);
return 1;
}
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
if (values != null && values.size() > 0) {
save(values);
return values.size();
}
String key = uri.getQueryParameter(PARAM_KEY);
String value = uri.getQueryParameter(PARAM_VALUE);
if (!TextUtils.isEmpty(key)) {
save(key, value);
return 1;
}
return 0;
}
protected String getValue(String key, String defValue) {
return mStore.getString(key, defValue);
}
protected void save(ContentValues values) {
String key;
String value;
Iterator<String> iterator = values.keySet().iterator();
SharedPreferences.Editor editor = mStore.edit();
while (iterator.hasNext()) {
key = iterator.next();
value = values.getAsString(key);
if (!TextUtils.isEmpty(key)) {
if (value != null) {
editor.putString(key, value);
} else {
editor.remove(key);
}
}
}
editor.commit();
}
protected void save(String key, String value) {
SharedPreferences.Editor editor = mStore.edit();
if (value != null) {
editor.putString(key, value);
} else {
editor.remove(key);
}
editor.commit();
}
protected void remove(String key) {
SharedPreferences.Editor editor = mStore.edit();
editor.remove(key);
editor.commit();
}
}
2、在【A程序】的注册清单中<application>内添加provider属性
<provider
android:exported = "true"
android:authorities = "com.carshow.provider"//此处一定要和前面添加的CustomProvider类中设置的URI名字一致
android:name = "com.hades.toolkit.utils.CustomProvider"/>
3、在需要调用其他应用共享数据的程序中【B程序】也添加上述CustomProvider类,但不需要在注册清单中添加provider属性,记住,两个程序中的CustomProvider类中AUTHORITY_URI 参数的包名一定要一致,可以将类直接从【A程序】中复制到【B程序】中,不用更改任何参数
4、完成上述操作后可直接使用
在【A程序】中存储数据:
CustomProvider.save(this, "RightFront", 6);//第一个参数是Context,第二个参数是Key,第三个参数是要保存的值,值的类型我在上面CustomProvider类中只添加了String和int两种类型,也可以根据需求新建方法。
在【B程序】中读取数据:
int vaue = CustomProvider.getInt(this, "RightFront", 0);//第三个参数是默认值
完成!