浅谈Android四大组件之ContentProvider

1 介绍

ContentProvider作为Android中的四大组件之一其主要作用是暴露出私有的数据供其它应用使用,比如一个应用程序需要读取手机里的手机联系人供自己使用。由此我们可以知道,这是也是一种Android中进程之间的通信方式。内容提供者在开发中自己写不多。更多的是访问内容提供者,一般都是访问系统的内容提供者

2 简单案例

新建一个应用工程,实现sqllite初始化:

 public class MySqliteopenhelper extends SQLiteOpenHelper {

    public MySqliteopenhelper(Context context) {
        super(context, "test.db", null, 1);
        // TODO Auto-generated constructor stub
    }

    //第一次创建的时候调用
    //特别适合  初始化
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table person (_id integer primary key autoincrement,name varchar(20),age varchar(20) )");
        db.execSQL("insert into person (name,age) values('赵日天','9')");
        db.execSQL("insert into person (name,age) values('刘斩仙','10')");
        db.execSQL("insert into person (name,age) values('李杀神','7')");
        db.execSQL("insert into person (name,age) values('王诛魔','8')");
    }
    //版本更新的时候调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub

    }
 }

新建ContentProvider实现类MyProvider:

public class MyProvider extends ContentProvider {

    private static final int QUERY = 1;
    // 1.在清单文件中配置 需要android:authorities="cn.test.provider" android 4.4以上版本需要额外配置 android:exported="true" 
    // 2.添加uri的匹配器
    private static final UriMatcher urimatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int INSERT = 2;
    private static final int DELETE = 3;
    private static final int UPDATE = 4;
    private MySqliteopenhelper helper;
    static {
        // authority 就是在清单文件中配置 的android:authorities="cn.test.provider"
        // authority 相当于主机名 www.baidu.com
        // path 二级路径 相当于 www.baidu.com/news 的news
        // code 匹配成功以后的返回码 必须正数
        urimatcher.addURI("cn.test.provider", "query", QUERY);
        urimatcher.addURI("cn.test.provider", "insert", INSERT);
        urimatcher.addURI("cn.test.provider", "delete", DELETE);
        urimatcher.addURI("cn.test.provider", "update", UPDATE);
    }

    @Override
    public boolean onCreate() {
        // getContext() 内容提供者获取 上下文的方法

        helper = new MySqliteopenhelper(getContext());
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        // 匹配uri 匹配成功了以后才去 操作数据库
        int match = urimatcher.match(uri);
        if (match == QUERY) {
            SQLiteDatabase db = helper.getReadableDatabase();
            // projection 要查询的列名
            Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);

            //数据不要关
//          db.close();
            return cursor;
        } else {
            throw new IllegalArgumentException("大熊第!你的uri 好像有点问题哦");
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {

        // 判断 匹配码
        int match = urimatcher.match(uri);
        if (match == INSERT) {
            SQLiteDatabase db = helper.getWritableDatabase();

            // insert2 数据添加到了 第几行
            long insert2 = db.insert("person", null, values);
            db.close();
            return Uri.parse("cn.test/" + insert2);
        } else {
            throw new IllegalArgumentException("大兄弟!你的暗号没对上哦");
        }

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {

        if (urimatcher.match(uri) == DELETE) {
            SQLiteDatabase db = helper.getWritableDatabase();

            // 刪除 delete2 刪除影响了几行
            int delete2 = db.delete("person", selection, selectionArgs);

            db.close();

            return delete2;
        }
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

        if (urimatcher.match(uri) == UPDATE) {
            SQLiteDatabase db = helper.getWritableDatabase();
            // 更新数据  update2 修改影响力几行
            int update2 = db.update("person", values, selection, selectionArgs);

            db.close();
            return update2;
        }
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return null;
    }
}

注册清单:

    <provider
            android:name="cn.test.whycontentprovider.MyProvider"
            android:authorities="cn.test.provider" 
            android:exported="true">
        provider>

这时我们再新建一个新的应用工程写四个按钮实现对内容提供者的查询,增加,删除,修改操作:

// 内容提供者查询其他应用的数据库

public void click1(View v) {

        // content:// uri前面必须要添加
        Uri uri = Uri.parse("content://cn.test.provider/query");
        // 获取内容解析者
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);

        while (cursor.moveToNext()) {
            String _id = cursor.getString(0);
            String name = cursor.getString(1);
            String age = cursor.getString(2);
            System.out.println("内容提供者查询的数据" + " " + _id + " " + name + " " + age);
        }
        cursor.close();
    }

    // 内容提供者增加其他应用的数据库
    public void click2(View v) {
        Uri url = Uri.parse("content://cn.test.provider/insert");
        ContentValues values = new ContentValues();
        values.put("name", "叶良辰");
        values.put("age", "15");
        // 获取内容解析者
        Uri insert = getContentResolver().insert(url, values);
        System.out.println(insert);
    }

    // 内容提供者删除其他应用的数据库
    public void click3(View v) {
        Uri url = Uri.parse("content://cn.test.provider/delete");
        int delete = getContentResolver().delete(url, "_id=?", new String[] { "2" });
        System.out.println(delete);
    }

    // 内容提供者修改其他应用的数据库
    public void click4(View v) {
        Uri url = Uri.parse("content://cn.test.provider/update");
        ContentValues values = new ContentValues();
        values.put("age", "99");
        int update = getContentResolver().update(url, values, "_id=?", new String[] { "1" });
        System.out.println(update);
    }

3 内容提供者案例-读取联系人

步骤 :
首先 查询 raw_contacts 表 查到contact_id 就是data表 raw_contact_id
然后 根据raw_contact_id 查询data1 和mimetype
最后 根据mimetype 来区分data1的内容

/**
     * 通过 内容提供者查询联系人
     * 
     * @param context
     *            上下文
     * 
     * @return 联系人的集合
     */
    public List queryContacts(Context context) {
        List infos = null;
        // 1 查询raw_contacts 表 查询contact_id
        // 1>查询raw_contacts 的uri 去源码 清单文件和 源码找到路径
        // android:authorities="contacts;com.android.contacts" contacts 以前使用
        // com.android.contacts 新的authorities
        // matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts",
        // RAW_CONTACTS);
        // 2 根据查到的contact_id 也就是 data 表中的 raw_contact_id去查询data表 查询 data1
        // mimetype
        // 3使用mimetype_id 去区分查到的 data1的数据
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri datauri = Uri.parse("content://com.android.contacts/data");
        /// 1 查询raw_contacts 表 查询contact_id 全查询出来
        Cursor cursor = context.getContentResolver().query(uri, new String[] { "contact_id" }, null, null, null);
        if (cursor != null && cursor.getCount() > 0) {
            // 初始化集合
            infos = new ArrayList<>();
            while (cursor.moveToNext()) {
                String contact_id = cursor.getString(0);
                System.out.println(contact_id);
                // 查询所有的列名
                // Cursor cursor2 = getContentResolver().query(datauri, null,
                // null, null, null);
                // //查询cursor中的所有的列名
                // String[] columnNames = cursor2.getColumnNames();
                // for (String string : columnNames) {
                // System.out.println(string);
                // }
                // 没查询到一个contact_id 都要去查一次 data表 查 data1 和 mimetype_id
                // mimetype_id 在data表中并没有 而是有mimetype
                //记得进行非空判断   数据库并没有删除这条数据 而是置为null
                if (contact_id!=null) {
                    Cursor datacursor = context.getContentResolver().query(datauri,
                            new String[] { "data1", "mimetype" }, "raw_contact_id=?", new String[] { contact_id },
                            null);
                    if (datacursor != null && datacursor.getCount() > 0) {
                        // 这里进来说明有联系人的数据 可以创建联系人的对象
                        ContactInfo info = new ContactInfo();
                        // 循环取出每条数据
                        // 循环取出
                        while (datacursor.moveToNext()) {
                            String data1 = datacursor.getString(0);
                            String mimetype = datacursor.getString(1);
                            // 3 使用mimetype 区分获取的数据
                            if (mimetype.equals("vnd.android.cursor.item/phone_v2")) {
                                // System.out.println("联系人的电话是:" + data1);
                                info.setPhone(data1);
                            }
                            if (mimetype.equals("vnd.android.cursor.item/name")) {
                                // System.out.println("联系人的姓名是:" + data1);
                                info.setName(data1);
                            }
                            if (mimetype.equals("vnd.android.cursor.item/nickname")) {
                                // System.out.println("联系人的昵称是:" + data1);
                                info.setNickname(data1);
                            }
                            if (mimetype.equals("vnd.android.cursor.item/email_v2")) {
                                // System.out.println("联系人的邮箱是:" + data1);
                                info.setEmail(data1);
                            }
                        }
                        datacursor.close();
                        infos.add(info);
                    }
                }
            }
        }
        cursor.close();
        return infos;
    }

4 内容观察者

内容观察者是为了在内容提供者处通知

内容使用处:
      Uri uri=Uri.parse("content://cn.test.provider/query");
        //注册内容观察者   通过 内容解析者
        //notifyForDescendents  ture 不是非常严格 检测URI 和false 非常严格检查uri
        getContentResolver().registerContentObserver(uri, true, new MyContenObserver(new Handler()));



 class MyContenObserver extends ContentObserver{

        //handler  需要更新UI
        public MyContenObserver(Handler handler) {
            super(handler);
            // TODO Auto-generated constructor stub
        }

        //selfChange  是否是自己应用的内容提供者发生变化
        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            System.out.println("数据库发生了变化");
        }

    }

内容提供者
提供数据处

    `getContext().getContentResolver().notifyChange(uri,null);`
observer 是否指定专门的观察者  null 不指定专门的观察者。

你可能感兴趣的:(Android,基础)