Android组件之Content Provider

本文深入讲解了安卓系统中ContentProvider的原理与应用,包括其基本概念、如何创建及使用示例。并提供了一个完整的笔记应用案例,展示了如何利用ContentProvider进行数据共享。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是ContentProvider?

ContentProvider是安卓的四大组件之一,主要的作用就是和第三方应用共享数据,其他应用也可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的如联系人和图片等数据。

Google Doc中对ContentProvider的大致概述:

内容提供者将一些特定的应用程序数据供给其它应用程序使用。内容提供者继承于ContentProvider 基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。

2.ContentProvider的创建?

public class MyContentProvider extends ContentProvider{

    @Override
    public boolean onCreate() {//在创建ContentProvider时调用
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {//用于查询指定Uri的ContentProvider,返回一个Cursor
        return null;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {//用于返回指定的Uri中的数据的MIME类型
        return null;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {//用于添加数据到指定Uri的ContentProvider中
        return null;
    }

    @Override
    public int delete(Uri uri, String s, String[] strings) {//用于从指定Uri的ContentProvider中删除数据
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {//用于更新指定Uri的ContentProvider中的数据
        return 0;
    }
}

3.实例代码

先来设计一个数据库,用来存储笔记信息,主要包含_ID,title,content,create_date四个字段。创建NoteProviderMetaData类,封装URI和数据库、表、字段相关信息,源码如下:

public class NoteProviderMetaData {
    public static final String AUTHORITY = "com.keyi.mycontentprovider.NoteProvider";

    public static final String DATABASE_NAME = "note.db";
    public static final int DATABASE_VERSION = 1;

    /**
     *      *
     *      *数据库中表相关的元数据
     *      
     */
    public static final class NoteTableMetaData implements BaseColumns {

        public static final String TABLE_NAME = "notes";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.alexzhou.note";
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.alexzhou.note";

        public static final String NOTE_TITLE = "title";
        public static final String NOTE_CONTENT = "content";
        public static final String CREATE_DATE = "create_date";

        public static final String DEFAULT_ORDERBY = "create_date DESC";

        public static final String SQL_CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + _ID + " INTEGER PRIMARY KEY,"
                + NOTE_TITLE + " VARCHAR(50),"
                + NOTE_CONTENT + " TEXT,"
                + CREATE_DATE + " INTEGER"
                + ");";
    }
}
内容提供者和数据库
public class MyContentProvider extends ContentProvider {
    private static final UriMatcher sUriMatcher;
    private static final int COLLECTION_INDICATOR = 1;
    private static final int SINGLE_INDICATOR = 2;
    private DatabaseHelper mDbHelper;

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NoteProviderMetaData.AUTHORITY, "notes", COLLECTION_INDICATOR);
        sUriMatcher.addURI(NoteProviderMetaData.AUTHORITY, "notes/#", SINGLE_INDICATOR);
    }

    private static HashMap<String, String> sNotesProjectionMap;

    static {
        sNotesProjectionMap = new HashMap<String, String>();
        sNotesProjectionMap.put(NoteProviderMetaData.NoteTableMetaData._ID, NoteProviderMetaData.NoteTableMetaData._ID);
        sNotesProjectionMap.put(NoteProviderMetaData.NoteTableMetaData.NOTE_CONTENT, NoteProviderMetaData.NoteTableMetaData.NOTE_CONTENT);
        sNotesProjectionMap.put(NoteProviderMetaData.NoteTableMetaData.NOTE_TITLE, NoteProviderMetaData.NoteTableMetaData.NOTE_TITLE);
        sNotesProjectionMap.put(NoteProviderMetaData.NoteTableMetaData.CREATE_DATE, NoteProviderMetaData.NoteTableMetaData.CREATE_DATE);
    }

    @Override
    public boolean onCreate() {//在创建ContentProvider时调用
        mDbHelper = new DatabaseHelper(this.getContext());
        return true;
    }

    //实现query方法,这里借助SQLiteQueryBuilder来为查询设置投影映射以及设置相关查询条件,
    // 返回的是一个Cursor对象,它是一个行集合,包含0和多个记录,类似于JDBC中的ResultSet,可以前后移动游标,
    // 得到每行每列中的数据。注意的是,使用它需要调用moveToFirst(),因为游标默认是在第一行之前。
    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {//用于查询指定Uri的ContentProvider,返回一个Cursor
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        switch (sUriMatcher.match(uri)) {
            case COLLECTION_INDICATOR:
                // 设置查询的表
                queryBuilder.setTables(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME);
                // 设置投影映射
                queryBuilder.setProjectionMap(sNotesProjectionMap);
                break;

            case SINGLE_INDICATOR:
                queryBuilder.setTables(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME);
                queryBuilder.setProjectionMap(sNotesProjectionMap);
                queryBuilder.appendWhere(NoteProviderMetaData.NoteTableMetaData._ID + "=" + uri.getPathSegments().get(1));
                break;

            default:
                throw new IllegalArgumentException("Unknow URI: " + uri);
        }

        String orderBy;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = NoteProviderMetaData.NoteTableMetaData.DEFAULT_ORDERBY;
        } else {
            orderBy = sortOrder;
        }
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, orderBy);

        return cursor;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {//用于返回指定的Uri中的数据的MIME类型
        switch(sUriMatcher.match(uri)) {
            case COLLECTION_INDICATOR:
                return NoteProviderMetaData.NoteTableMetaData.CONTENT_TYPE;

            case SINGLE_INDICATOR:
                return NoteProviderMetaData.NoteTableMetaData.CONTENT_ITEM_TYPE;

            default:
                throw new IllegalArgumentException("Unknow URI: " + uri);
        }
    }

    //实现insert方法,实现把记录插入到基础数据库中,然后返回新创建的记录的URI
    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {//用于添加数据到指定Uri的ContentProvider中
        if (sUriMatcher.match(uri) != COLLECTION_INDICATOR) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        long rowID = db.insert(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME, null, values);

        if (rowID > 0) {
            Uri retUri = ContentUris.withAppendedId(NoteProviderMetaData.NoteTableMetaData.CONTENT_URI, rowID);
            return retUri;
        }
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {//用于从指定Uri的ContentProvider中删除数据
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        int count = -1;
        switch(sUriMatcher.match(uri)) {
            case COLLECTION_INDICATOR:
                count = db.delete(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME, selection, selectionArgs);
                break;

            case SINGLE_INDICATOR:
                String rowID = uri.getPathSegments().get(1);
                count = db.delete(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME, NoteProviderMetaData.NoteTableMetaData._ID + "=" + rowID, null);
                break;

            default:
                throw new IllegalArgumentException("Unknow URI :" + uri);

        }
        // 更新数据时,通知其他ContentObserver
        this.getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    //实现update方法,根据传入的列值和where字句来更新记录,返回更新的记录数,
    @Override
    public int update(Uri uri, ContentValues values, String s, String[] strings) {//用于更新指定Uri的ContentProvider中的数据
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        int count = -1;
        switch (sUriMatcher.match(uri)) {
            case COLLECTION_INDICATOR:
                count = db.update(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME, values, null, null);
                break;

            case SINGLE_INDICATOR:
                String rowID = uri.getPathSegments().get(1);
                count = db.update(NoteProviderMetaData.NoteTableMetaData.TABLE_NAME, values, NoteProviderMetaData.NoteTableMetaData._ID + "=" + rowID, null);
                break;

            default:
                throw new IllegalArgumentException("Unknow URI : " + uri);
        }
        this.getContext().getContentResolver().notifyChange(uri, null);//notifyChange函数是在更新数据时,通知其他监听对象。
        return count;
    }


    private static class DatabaseHelper extends SQLiteOpenHelper {

        public DatabaseHelper(Context context) {
            super(context, NoteProviderMetaData.DATABASE_NAME, null, NoteProviderMetaData.DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.e("DatabaseHelper", "create table: " + NoteProviderMetaData.NoteTableMetaData.SQL_CREATE_TABLE);
            db.execSQL(NoteProviderMetaData.NoteTableMetaData.SQL_CREATE_TABLE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + NoteProviderMetaData.NoteTableMetaData.TABLE_NAME);
            onCreate(db);
        }

    }
}

最后是测试代码:

public class MainActivity extends Activity {
    public static final String AUTHORITY = "com.keyi.mycontentprovider.NoteProvider";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        insert();
        query();
    }
    private void insert() {
        ContentValues values = new ContentValues();
        values.put("title", "hello");
        values.put("content", "my name is alex zhou");
        long time = System.currentTimeMillis();
        values.put("create_date", time);
        Uri uri = this.getContentResolver().insert(CONTENT_URI, values);
        Log.e("test ", uri.toString());
    }
    private void query() {
        Cursor cursor = this.getContentResolver().query(CONTENT_URI, null, null, null, null);
        Log.e("test ", "count=" + cursor.getCount());
        cursor.moveToFirst();
        while(!cursor.isAfterLast()) {
            String title = cursor.getString(cursor.getColumnIndex("title"));
            String content = cursor.getString(cursor.getColumnIndex("content"));
            long createDate = cursor.getLong(cursor.getColumnIndex("create_date"));
            Log.e("test ", "title: " + title);
            Log.e("test ", "content: " + content);
            Log.e("test ", "date: " + createDate);
            cursor.moveToNext();
        }
        cursor.close();
    }
}

需要在AndroidManifest.xml中注册:

<provider android:name=".MyContentProvider"
    android:authorities="com.keyi.mycontentprovider.NoteProvider"/>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值