小谈Android四大组件之ContentProvider

内容提供者详解

内容提供者的作用

1.应用程序创建的数据库默认都是私有的,别的应用程序不可以访问里面的数据.

2.如果需要把自己应用程序私有的数据库暴露给别的用户增删改查,就需要使用内容提供者.

3.作用: 一个应用程序访问另外一个应用程序在硬盘上存储的数据

注:ContentProvider可以理解为:应用程序数据库的后门.

编写ContentProvider的流程

创建一个自定义内容提供者的Android项目:

1.写一个类继承ContentProvider, 重写的所有方法(主要是增删改查)默认都是空实现.

2.在清单文件下声明provider. 必须指定主机名!!!

<provider 
    android:name="内容提供者的包名"
    android:authorities="自定义主机名"><provider/>
注:主机名也就是对外提供的uri,可以任意自定义,一般的规则是应用程序包名.

3.在内容提供者代码内部定义UriMatcher -用于判断uri是否匹配

//使用静态变量和代码块,便于自动加载.
static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
mUriMatcher.addURI("在清单文件里面定义的authorities", "自定义匹配字符串", 成功返回的标识);
}

注:1.自定义匹配字符串规则: 一般使用被操作的数据库中的表名.
   2.成功返回标识:SUCCESS, ERROR

4.在内容提供者执行增删改查方法时,判断uri是否合法

int code=matcher.match(uri);
if(code==SUCCESS){
    //数据库增删改查的逻辑
}else{
    throw new IllegalArgumentException("口令不正确,")
}   

5.实例化数据

MyDBHelper helper = new MyDBHelper(this);
helper.getWritableDatabase();

再创建另一个Android项目访问内容提供者:

在MainActivity里写对数据库增删改查的逻辑方法

1.创建内容提供者解析器
ContentResolver resolver=上下文.getContentResolver();
2.定义要访问的Uri路径
Uri uri = Uri.parse("content://自定义主机名/自定义匹配字符串")
//注意:content://是标准写法
3.通过内容解析器执行操作:增,删,改,查
如添加:resolver.insert(uri, values);

小结:

    1.写一个类继承ContentProvider,实现增删改查的方法
    2.在清单文件中配置内容提供者,指定android:authorities="com.yashiro.database"
    3.在内容提供者代码的内部,声明uriMatcher
    4.通过uriMatcher检查uri的路径是否正确
    5.在另外一个应用程序里面,通过contentResolver 增删改查

案例

<案例一: 用内容提供者操作系统短信>

思路: 直接访问系统短信应用的内容提供者,实现对短信应用数据库的增加和删除操作.

步骤:

1.通过查找系统源码,可以确定短信息内容提供者的Uri 应该为:content://sms
2.查看Android 模拟器下的/data/data/com.android.providers.telephony/databases/目录,查看其mmssms.db文件,确定sms表存储的数据格式:
    *其中,address 存储的是联系人号码,date 是发送日期,type 对应短信的类型(发送是1/接收是2),body是短信的主体内容。
3.创建一个Android项目,在MainActivity里写删除和添加短信的业务逻辑
    1).配置清单文件,添加短信的读写权限
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.WRITE_SMS"/>

    2).实现添加和删除业务逻辑

        /**
     * 利用内容提供者,添加短信
     * 
     * @param view
     */
    public void add(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://sms");
        ContentValues values = new ContentValues();
        values.put("address", "110");
        values.put("type", 1);
        values.put("date", System.currentTimeMillis());
        values.put("body", "小子诶....你小心了,我们盯上你le~~");
        resolver.insert(uri, values);
        Toast.makeText(this, "添加成功", 0).show();
    }

    /**
     * 利用内容提供者,删除短信
     * 
     * @param view
     */
    public void delete(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://sms");
        resolver.delete(uri, "address=?", new String[] { "110" });
        Toast.makeText(this, "删除成功", 0).show();
    }

<案例二: 用内容提供者操作系统联系人>

开发现状:

现在很多App 都可以对系统联系人进行操作,比如微信就可以直接将号码添加到系统联系人中,比如QQ 可以关联/备份/恢复系统联系人。

完成这些操作,需要能够访问并修改系统联系人的数据库.

思路: 直接访问系统联系人应用的内容提供者,实现对联系人数据的增加和删除操作.

步骤:

1.打开Android 源码,查看packages\providers\路径下的文件,其中ContactsProvider 就是联系人的内容提供者.找到清单文件,发现内容提供者的类名为ContactsProvider2.java.

这里写图片描述

2.根据原码确定Uri信息如下:

操作raw_contacts 表的Uri:
content://com.android.contacts/raw_contacts
操作data 表的Uri:
content://com.android.contacts/data

3.注意事项:

*由于contacts2.db 数据库使用了视图,所以操作数据库表时,看到的表字段名称和真实操作的有所不同。
*比如:data 表在查询的时候没有mimetype_id 字段,取代的是mimetype 字段。
*使用指南:
    1.查询raw_contact表 获取联系人的contact_id.
    2.根据contact_id查询data表,获取联系人的数据
    3.根据mimetype确定数据的类型

4.查询手机联系人

步骤:

1).创建一个项目,配置清单文件,添加读取联系人的权限

android:readPermission="android.permission.READ_CONTACTS"

2).创建一个联系人bean,有信息name,phone,Email,QQ.

3).创建一个联系人工具类,获取所有的联系人信息,放到一个List集合中返回.

    public class ContactInfoUtils {
    /**
     * 获取所有的联系人信息
     * 
     * @param context
     *            上下文
     * @return
     */
    public static List<ContactInfo> getAllContactInfos(Context context) {
        List<ContactInfo> infos = new ArrayList<ContactInfo>();
        ContentResolver resolver = context.getContentResolver();
        // 查询raw_contact表
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri datauri = Uri.parse("content://com.android.contacts/data");
        Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
                null, null, null);
        //根据游标判断是否有数据
        while (cursor.moveToNext()) {
            String id = cursor.getString(0);
            System.out.println("Id:" + id);
            if (id != null) {
                ContactInfo info = new ContactInfo();
                // 查询data表
                Cursor datacursor = resolver.query(datauri, new String[] {
                        "data1", "mimetype" }, "raw_contact_id=?",
                        new String[] { id }, null);
                //根据游标判断是否有数据
                while (datacursor.moveToNext()) {
                    String data1 = datacursor.getString(0);
                    String mimetype = datacursor.getString(1);
                    if ("vnd.android.cursor.item/name".equals(mimetype)) {
                        info.setName(data1);
                    } else if ("vnd.android.cursor.item/im".equals(mimetype)) {
                        info.setQq(data1);
                    } else if ("vnd.android.cursor.item/email_v2"
                            .equals(mimetype)) {
                        info.setEmail(data1);
                    } else if ("vnd.android.cursor.item/phone_v2"
                            .equals(mimetype)) {
                        info.setPhone(data1);
                    }
                }
                datacursor.close();
                infos.add(info);
            }
        }
        cursor.close();
        return infos;
    }

}

4).在MainActiviry里获取联系人信息的集合,并显示到界面上

infos = ContactInfoUtils.getAllContactInfos(this);
ListView lv = (ListView) findViewById(R.id.lv);
//设置适配器
lv.setAdapter(new BaseAdapter() {
    @Override
    public int getCount() {
        return infos.size();
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView tv = new TextView(MainActivity.this);
        tv.setText(infos.get(position).toString());
        return tv;
    }
    ...

5.添加手机联系人

步骤:

1).新建一个Android项目,配置清单文件

 <!-- 读取联系人 写入联系人 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

2).设置布局文件,获取用户录入的姓名,电话,邮箱信息

<EditText
        android:id="@+id/et_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="姓名" />

    <EditText
        android:id="@+id/et_phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="电话" />

    <EditText
        android:id="@+id/et_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="邮箱" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="save"
        android:text="保存数据" />'

3).在MainActivity里写实现添加的业务逻辑

    public class MainActivity extends Activity {

    private EditText et_name;
    private EditText et_phone;
    private EditText et_email;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //关心控件
        et_name = (EditText) findViewById(R.id.et_name);
        et_phone = (EditText) findViewById(R.id.et_phone);
        et_email = (EditText) findViewById(R.id.et_email);
    }

    public void save(View view) {
        //获取输入信息
        String name = et_name.getText().toString().trim();
        String phone = et_phone.getText().toString().trim();
        String email = et_email.getText().toString().trim();
        //定义要访问的Uri路径
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri datauri = Uri.parse("content://com.android.contacts/data");
        //获取游标
        Cursor cursor = getContentResolver().query(uri, new String[] { "_id" },
                null, null, "_id desc");
        //游标初始化到开始位置
        cursor.moveToFirst();
        int _id = cursor.getInt(0);
        int newId = _id + 1;
        //文本数据
        ContentValues values = new ContentValues();
        values.put("contact_id", newId);
        //根据uri添加数据
        getContentResolver().insert(uri, values);

        // 往data表里面添加数据.
        // 1.添加name
        ContentValues nameValue = new ContentValues();
        nameValue.put("raw_contact_id", newId);
        nameValue.put("data1", name);
        nameValue.put("mimetype", "vnd.android.cursor.item/name");
        getContentResolver().insert(datauri, nameValue);

        // 2.添加email
        ContentValues emailValue = new ContentValues();
        emailValue.put("raw_contact_id", newId);
        emailValue.put("data1", email);
        emailValue.put("mimetype", "vnd.android.cursor.item/email_v2");
        getContentResolver().insert(datauri, emailValue);

        // 3.添加phone
        ContentValues phoneValue = new ContentValues();
        phoneValue.put("raw_contact_id", newId);
        phoneValue.put("data1", phone);
        phoneValue.put("mimetype", "vnd.android.cursor.item/phone_v2");
        getContentResolver().insert(datauri, phoneValue);

        Toast.makeText(this, "添加数据成功", 0).show();
    }
}

内容观察者 ContentObserver

•观察数据库内容是否发生改变,如果改变,通知观察者

使用步骤:

1.在内容提供者ContentProvider的增删改查方法中,增加通知的方法:

getContext().getContentResolver().notifyChange(uri, null);

2.在观察者类注册观察者,监控内容提供者的方法

//定义观察的uri
Uri uri = Uri.parse("content://被观察的主机名/数据库表名");
//注册观察者
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {

            @Override
            public void onChange(boolean selfChange) {
                System.out.println("我是观察者,我发现银行的数据库变化了.");
                super.onChange(selfChange);
            }

        });

小结:

内容观察者一般配合内容提供者一起使用.让内容提供者即向另外的一个程序暴露了私有的数据库,又将数据库的变化情况告诉给了观察者.

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值