0
点赞
收藏
分享

微信扫一扫

ContentProvider


目录

  • ​​ContentProvider 如何实现数据共享​​
  • ​​为什么要用 ContentProvider? 它和 sql 的实现上有什么差别?​​
  • ​​ContentProvider、ContentResolver、ContentObserver 之间的关系​​
  • ​​如何访问 asserts 资源目录下的数据库?​​
  • ​​如何在高并发下进行数据库查询​​
  • ​​案例-查询联系人​​
  • ​​案例-完整的使用​​
  • ​​步骤一、server app中定义ContentProvider​​
  • ​​步骤二、server app清单文件中注册​​
  • ​​步骤三、client app调用provider​​
  • ​​client app中使用ContentObserver​​
  • ​​数据实体​​
  • ​​数据库操作​​

ContentProvider 如何实现数据共享

  • Android 中如果想将自己应用的数据(一般多为数据库中的数据)提供给第三发 app,那么我们只能通过 ContentProvider 来实现
  • ContentProvider 是应用程序之间共享数据的接口. 使用的时候首先自定义一个类继承 ContentProvider,然后覆写 ​​query​​、​​insert​​、​​update​​、​​delete​​ 等方法. 最后别忘了作为 android 四大组件之一必须在 AndroidManifest 文件中进行注册
  • 第三方 app 可以通过 ContentResolver 类来访问该 Provider
  • 第三方 app 可以通过注册 ContentObserver 观测该Provider操作后的数据库变化

为什么要用 ContentProvider? 它和 sql 的实现上有什么差别?

  • ContentProvider 屏蔽了数据存储的细节,内部实现对用户完全透明,用户只需要关心操作数据的 uri 就可以了,ContentProvider 可以实现不同 app 之间共享
  • Sql 也有增删改查的方法,但是 sql 只能查询本应用下的数据库. 而 ContentProvider 还可以去增删改查本地文件、.xml 文件的读取等

ContentProvider、ContentResolver、ContentObserver 之间的关系

  • ContentProvider:内容提供者,用于对外提供数据
  • ContentResolver.notifyChange(uri)​:发出消息
  • ContentResolver:内容解析者,用于获取内容提供者提供的数据
  • ContentObserver:内容监听器,可以监听数据的改变状态
  • ContentResolver.registerContentObserver()​:监听消息

如何访问 asserts 资源目录下的数据库?

  • 获取 assert 目录下的 db 文件

AssetManager assetManager = getAssets(); 
InputStream is = assetManager.open("myuser.db");
// 将文件拷贝到 /data/data/cc.catface.android.asserts.sqlite/databases/myuser.db
// 如果 databases 目录不存在则创建
File file = new File("/data/data/cc.catface.android.asserts.sqlite/databases");
if (!file.exists()) {
file.mkdirs();
}
FileOutputStream fos = new FileOutputStream(new File(file, "myuser.db"));
byte[] buff = new byte[1024 * 8];
int len = -1;
while((len = is.read(buff)) != -1){
fos.write(buff, 0, len);
}
fos.close();
is.close();

  • 访问数据库

SQLiteDatabase database = openOrCreateDatabase("myuser.db", MODE_PRIVATE, null);
String sql = "select c_name from t_user";
Cursor cursor = database.rawQuery(sql, null);
while(cursor.moveToNext()){
String string = cursor.getString(0);
Log.d("tag", string);
}
cursor.close();
database.close();

如何在高并发下进行数据库查询

  不要关联多表查询,减少链接时间,创建索引、将查询到的数据采用缓存策略等等

案例-查询联系人

  1. 动态申请权限
  • 清单文件中添加权限申明

<uses-permission android:name="android.permission.READ_CONTACTS" />

  • 代码中动态申请权限

if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 1);
}

  1. 获取联系人

Cursor cursor = null;
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.d("catface", "读取联系人:" + displayName + " || " + number);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}

案例-完整的使用

步骤一、server app中定义ContentProvider

public class FileProvider extends ContentProvider {
private final String TAG = "catface";

private static final Pair<String, Integer> TABLE_TEXT = new Pair<>("table_text", 0);
private static final Pair<String, Integer> TABLE_AUDIO = new Pair<>("table_audio", 1);
private static final Pair<String, Integer> TABLE_VIDEO = new Pair<>("table_video", 2);


// 主机名
private static final String AUTHORITY = "cc.catface.provider.server";
private static final Uri HOST_URI = Uri.parse("content://" + AUTHORITY);

private static UriMatcher mUriMatcher;

// 本地匹配规则
static {
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, TABLE_TEXT.first, TABLE_TEXT.second);
mUriMatcher.addURI(AUTHORITY, TABLE_AUDIO.first, TABLE_AUDIO.second);
mUriMatcher.addURI(AUTHORITY, TABLE_VIDEO.first, TABLE_VIDEO.second);
}

public FileProvider() {
Log.d(TAG, "constructor...");
}

@Override
public boolean onCreate() {
Log.d(TAG, "create...");
return true;
}

@Nullable
@Override
public String getType(@NonNull Uri uri) {
int match = mUriMatcher.match(uri);
if (match == TABLE_TEXT.second) {
return TABLE_TEXT.first;
}
if (match == TABLE_AUDIO.second) {
return TABLE_AUDIO.first;
}
if (match == TABLE_VIDEO.second) {
return TABLE_VIDEO.first;
}
return null;
}

@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
// Log.d(TAG, "insert-->uri: " + uri + " || values's size: " + values.size()); // 打印所有入参
String tableName = getType(uri);
if (null == getContext() || null == values || null == tableName) return null;
if (tableName.equals(TABLE_TEXT.first)) {
TextInfo info = new TextInfo();
if (values.containsKey("uuid")) info.setUuid(values.getAsString("uuid"));
if (values.containsKey("text")) info.setText(values.getAsString("text"));
if (values.containsKey("create_time")) info.setCreateTime(values.getAsLong("create_time"));
if (values.containsKey("search_count")) info.setSearchCount(values.getAsInteger("search_count"));
long rowId = DBHelper.getInstance().getTextInfoDAO().insert(info);
getContext().getContentResolver().notifyChange(HOST_URI, null);
return ContentUris.withAppendedId(uri, rowId);
}
return null;
}

@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
// Log.d(TAG, "delete-->uri: " + uri + " || selection: " + selection + " || selectionArgs: " + Arrays.asList(selectionArgs).toString()); // 打印所有入参
getContext().getContentResolver().notifyChange(HOST_URI, null); // 数据库发生变化通知客户app的观察者
return DBHelper.getInstance().getTextInfoDAO().deleteByText(selectionArgs[0]);
}

@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
// Log.d(TAG, "update-->uri: " + uri + " || values's size: " + values.size() + " || selection: " + selection + " || selectionArgs: " + Arrays.asList(selectionArgs).toString()); // 打印所有入参
int rowId = DBHelper.getInstance().getTextInfoDAO().updateText(selectionArgs[0], selectionArgs[1]);
getContext().getContentResolver().notifyChange(HOST_URI, null);
return rowId;
}

@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
// Log.d(TAG, "query-->uri: " + uri + " || projection[]: " + Arrays.asList(projection).toString() + " || selection: " + selection + " || selectionArgs[]: " + Arrays.asList(selectionArgs).toString() + " || sortOrder: " + sortOrder); // 打印所有入参
Cursor cursor = DBHelper.getInstance().getTextInfoDAO().select4CP(-1, 0);
cursor.setNotificationUri(getContext().getContentResolver(), HOST_URI);
return cursor;
}
}

步骤二、server app清单文件中注册

<provider
android:name="cc.catface.provider.server.FileProvider"
android:authorities="cc.catface.provider.server"
android:enabled="true"
android:exported="true"
android:multiprocess="true" />

步骤三、client app调用provider

  1. uri

Uri uri = Uri.parse("content://cc.catface.provider.server/table_text");

ContentValues values = new ContentValues();
values.put("uuid", UUID.randomUUID().toString());
values.put("text", binding.etText.getText().toString().trim());
values.put("create_time", System.currentTimeMillis());
values.put("search_count", Integer.valueOf(binding.etCount.getText().toString()));
Uri insertUri = getContentResolver().insert(uri, values);
Log.d("catface", "insert-->insertUri: " + insertUri.toString());

int rowId = getContentResolver().delete(uri, null, new String[]{binding.etDeleteText.getText().toString().trim()});
Log.d("catface", "delete-->rowId: " + rowId);

int rowId = getContentResolver().update(uri, new ContentValues(), null, new String[]{binding.etOldText.getText().toString().trim(), binding.etNewText.getText().toString().trim()});
Log.d("catface", "update-->rowId: " + rowId);

Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (null == cursor) return;
while (cursor.moveToNext()) {
String text = cursor.getString(cursor.getColumnIndex("text"));
long create_time = cursor.getLong(cursor.getColumnIndex("create_time"));
Log.d("catface", "query: " + text + " || " + create_time);
}
cursor.close();

client app中使用ContentObserver

  1. 定义并初始化ContentObserver

class CustomObserver extends ContentObserver {
public CustomObserver(Handler handler) {
super(handler);
}

@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d("catface", "CustomObserver-->onChange-->uri: " + uri + " || selfChange: " + selfChange);
}
}

CustomObserver mProviderObserver = new CustomObserver(new Handler());

  1. 注册ContentObserver

getContentResolver().registerContentObserver(Uri.parse("content://cc.catface.provider.server/table_text"), true, mProviderObserver);

  1. 解注册ContentObserver

getContentResolver().unregisterContentObserver(mProviderObserver);

数据实体

@Entity(tableName = "text_info")
public class TextInfo {

@NonNull @PrimaryKey private String uuid;
private String text;
@ColumnInfo(name = "create_time") private long createTime;
@ColumnInfo(name = "search_count") private int searchCount;

// getter & setter
}

数据库操作

@Dao
public interface TextInfoDAO {

@Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(TextInfo info);

@Query("delete from text_info where text=:text")
int deleteByText(String text);

@Query("update text_info set text=:newText where text=:oldText")
int updateText(String oldText, String newText);

@Query("select * from text_info order by create_time desc limit :pageSize offset :pageSize * :page")
Cursor select4CP(int pageSize, int page);
}


举报

相关推荐

0 条评论