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,然后覆写 queryinsertupdatedelete 等方法. 最后别忘了作为 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);
      }
      
  2. 获取联系人

    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");
    
  2. 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());
    
  3. int rowId = getContentResolver().delete(uri, null, new String[]{binding.etDeleteText.getText().toString().trim()});
    Log.d("catface", "delete-->rowId: " + rowId);
    
  4. 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);
    
  5. 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());
    
  2. 注册ContentObserver

    getContentResolver().registerContentObserver(Uri.parse("content://cc.catface.provider.server/table_text"), true, mProviderObserver);
    
  3. 解注册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);
}

你可能感兴趣的:(android_基础知识)