IPC机制<三>内容提供者

ContentProvider:内容提供者,它是android的四大组件之一。

android中数据库中的数据不能跨进程访问,但是有时候会有这种需求,例如微信访问联系人列表。这是怎么实现呢?用到的就是ContentProvider。

ContentProvider的创建

1、写一个类A继承ContentProvider

2、然后再清单文件AndroidManifest.xml中进行声明一下,其中anthorities是主机名称,可以随便起名,最好是包名,它是ContentProvider的唯一标识,通过这个属性外部应用就可以访问我们的定义的内容提供者。

<provider
     android:authorities="cn.demo.zx_provider_learn.dao"
     android:name=".dao.PersonProvider"
     android:exported="true"/>

3、继承ContentProvider的类中有四个操作数据库的方法,分别是怎删改查。如果数据库很多,那么怎样操作特定的数据库呢,那就需要通过传递的Uri来判断操作哪个数据库,所以想要了解这些东西之前需要明白URI、URL和URN。

Uri-Uniform Resourse Identifier-统一资源标识符,用来标识资源,例如,班级里有几十个同学,老师需要知道他们谁是谁。识别的方法有两种,URL和URN。

-Url-Uniform Resourse Location-统一资源位置,资源所在的位置来标识资源,例如:班级里第一排第一个位置的是张三。

-Urn-Uniform Resourse Name - 统一资源名称 ,资源的名称来标识资源,例如:班级里换了座位了,第一排第一个位置的不是张三了,但是老师还是能够识别出张三是哪个一个,原因就是识别他的方法不是靠位置,而是靠他的名称。

继承ContentProvider的类中需要用到UriMatcher来匹配传递过来的Uri。例如:

private static final int PERSON = 1;
/**
 * UriMatcher是Uri匹配器,如果传递过来的Uri不符合就返回-1
 * 如果传递过来的Uri是content://cn.demo.zx_provider_learn.dao/chaperson,那么返回
 */
public static UriMatcher matcher = new UriMatcher(-1);

/**
 * 添加Uri,如果传递的Uri在UriMatcher中存在,那么就说明可以有操作的方法,否则就没有
 * authority: 主机名,与清单文件AndroidManifest.xml中注册的一致
 * path:数据库的路径,可以随便起名,
 * code:如果匹配后返回的结果
 */
static {
    matcher.addURI("cn.demo.zx_provider_learn.dao","chaperson",PERSON);
}

举例:

PersonProvider:

public class PersonProvider extends ContentProvider {
    private static final int PERSON = 1;
    /**
     * 路径匹配,因为应用中可能有很多数据库,那么在ContentProvider中可能有操作不同数据库的方法
     * 那么你怎样调用操作特定数据库的方法呢?
     * 这里就需要使用UriMatcher方法
     */
    public static UriMatcher matcher = new UriMatcher(-1);

    /**
     * 添加需要判断的路径
     * authority: 主机名,与清单文件AndroidManifest.xml中注册的一致
     * path:数据库的路径,可以随便起名,
     * code:如果匹配后返回的结果
     */
    static {
        matcher.addURI("cn.demo.zx_provider_learn.dao","chaperson",PERSON);
    }

    MySQLiteOpenHelper mHelper = null;

    @Override
    public boolean onCreate() {
        mHelper = new MySQLiteOpenHelper(getContext());
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        if(matcher.match(uri)==PERSON){
            SQLiteDatabase db = mHelper.getReadableDatabase();
            return db.query("person",projection,selection,selectionArgs,null,null,sortOrder);
        }else{
            throw new IllegalArgumentException("这个Uri不处理。。。。。。。。。。。");
        }
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        if(matcher.match(uri)==PERSON) {
            SQLiteDatabase db = mHelper.getWritableDatabase();
            long insert = db.insert("person", null, values);
            return Uri.parse("content://cn.demo.zx_provider_learn.dao/chaperson/" + insert);
        }else{
            throw new IllegalArgumentException("这个Uri不处理。。。。。。。。。。。");
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        if(matcher.match(uri)==PERSON) {
            SQLiteDatabase db = mHelper.getWritableDatabase();
            int delete = db.delete("person", selection, selectionArgs);
            return delete;
        }else{
            throw new IllegalArgumentException("这个Uri不处理。。。。。。。。。。。");
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        if(matcher.match(uri)==PERSON) {
            SQLiteDatabase db = mHelper.getWritableDatabase();
            int update = db.update("person", values, selection, selectionArgs);
            return update;
        }else{
            throw new IllegalArgumentException("这个Uri不处理。。。。。。。。。。。");
        }
    }
}

AndroidMenifest:

<provider
     android:authorities="cn.demo.zx_provider_learn.dao"
     android:name=".dao.PersonProvider"
     android:exported="true"/>

调用者:

mUri = Uri.parse("content://cn.demo.zx_provider_learn.dao/chaperson");


/**
 * 增加
 * @param view
 */
public void add(View view){
    ContentValues values = new ContentValues();
    values.put("name","这是调用者");
    values.put("age",28);
    getContentResolver().insert(mUri,values);

}

/**
 * 删除
 * @param view
 */
public void delete(View view){
    getContentResolver().delete(mUri,"id=?",new String[]{1+""});
}

/**
 * 修改
 * @param view
 */
public void update(View view){
    ContentValues values = new ContentValues();
    values.put("name","小王八蛋");
    values.put("age",500);
    getContentResolver().update(mUri,values,"name=?",new String[]{"王八蛋"});
}

/**
 * 查
 * @param view
 */
public void find(View view){
    Cursor cursor = getContentResolver().query(mUri, null, null, null, null);
    while (cursor.moveToNext()){
        Person p = new Person();
        p.setId(cursor.getInt(cursor.getColumnIndex("id")));
        p.setName(cursor.getString(cursor.getColumnIndex("name")));
        p.setAge(cursor.getInt(cursor.getColumnIndex("age")));
        Toast.makeText(this, p.toString(), Toast.LENGTH_SHORT).show();
    }
}

备份短信

手机中的短信应用的数据结构(com.android.providers.telephony/databases/mmsms.db)

sms中几个重要的参数:

thread_id 会话编号

address 对方电话号码

date 时间

read 读取状态 0未读 1已读

type 类型 1接收 2发送

body 短信内容

步骤:

1、打开系统上层所有应用的源代码中的packages\providers\TelephonyProvider,找到并且打开清单文件AndroidMenifest.xml,找到操作短信的内容提供者

<provider android:name="SmsProvider"
          android:authorities="sms"
          android:multiprocess="true"
          android:readPermission="android.permission.READ_SMS"
          android:writePermission="android.permission.WRITE_SMS" />

2、打开SmsProvider.java文件,找到UriMatcher,很明显Uri是content://sms就是操作短信的标识符。

private static final UriMatcher sURLMatcher =
        new UriMatcher(UriMatcher.NO_MATCH);

static {
    sURLMatcher.addURI("sms", null, SMS_ALL);
    sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
    sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
    sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
    sURLMatcher.addURI("sms", "sent", SMS_SENT);
    sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
    sURLMatcher.addURI("sms", "draft", SMS_DRAFT);

3、获取短信:

/**
 * 短信备份
 * @param view
 */
public void backupSms(View view){
    new Thread(){
        @Override
        public void run() {
            super.run();
            List<SmsBean>list = new ArrayList<>();
            Cursor cursor = getContentResolver().query(Uri.parse("content://sms"), new String[]{"address", "date", "read", "body", "type"}, null, null, null);
            while (cursor.moveToNext()){
                SmsBean smsBean = new SmsBean();
                smsBean.setAddress(cursor.getString(cursor.getColumnIndex("address")));
                smsBean.setDate(cursor.getString(cursor.getColumnIndex("date")));
                smsBean.setRead(cursor.getString(cursor.getColumnIndex("read")));
                smsBean.setBody(cursor.getString(cursor.getColumnIndex("body")));
                smsBean.setType(cursor.getString(cursor.getColumnIndex("type")));
                Toast.makeText(this, smsBean.toString(), Toast.LENGTH_SHORT).show();
                System.out.println("短信::"+smsBean.toString());
                list.add(smsBean);
            }
        }
    }.start();
}

利用内容提供者操作联系人信息

应用中数据表结构:com.android.providers.contacts/databases/contacts2.db

数据库中几个重要的表

raw_contacts:

保存联系人编号

contact_id:联系人的id

data:

通讯录信息表,保存联系人的具体信息

raw_contact_id( 外键,指向raw_contacts中的contact_id ),当前信息所属的联系人的id

data1,所存储的信息

mimetype_id(外键,指向mimetypes中的_id),代表当前记录表示的信息类型

mimetypes:

信息类型表,存储了联系人信息的类型

_id 编号

mimetype 该编号表示的联系人信息类型

步骤

1、打开系统上层所有应用的源代码中的packages\providers\ContactsProvider,找到并且打开清单文件AndroidMenifest.xml,找到操作联系人的内容提供者

<provider android:name="ContactsProvider2"
        android:authorities="contacts;com.android.contacts"
        android:label="@string/provider_label"
        android:multiprocess="false"
        android:readPermission="android.permission.READ_CONTACTS"
        android:writePermission="android.permission.WRITE_CONTACTS">

2、打开ContactsProvider2.java文件,找到UriMatcher,通过UriMatcher找到查询raw_contacts表和data表的路径。

matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);

所以需要传递的Uri是:

content://com.android.contacts/raw_contacts
content://com.android.contacts/data

查询联系人

/**
 * 查询联系人
 * @param view
 */
public void findContacts(View view){
    //获取联系人个数
    Cursor cursor = getContentResolver().query(uri_raw_contact, null, null, null, null);
    while (cursor.moveToNext()){
        String contact_id = cursor.getString(cursor.getColumnIndex("contact_id"));
        Cursor c = getContentResolver().query(uri_data, null, "raw_contact_id=?", new String[]{contact_id}, null);
        ContactInfo info = new ContactInfo();
        while (c.moveToNext()){
            String mimetypes = c.getString(c.getColumnIndex("mimetype"));
            if("vnd.android.cursor.item/name".equals(mimetypes)){
                info.setName(c.getString(c.getColumnIndex("data1")));
            }else if("vnd.android.cursor.item/phone_v2".equals(mimetypes)){
                info.setPhone(c.getString(c.getColumnIndex("data1")));
            }else if("vnd.android.cursor.item/email_v2".equals(mimetypes)){
                info.setEmail(c.getString(c.getColumnIndex("data1")));
            }else if("vnd.android.cursor.item/organization".equals(mimetypes)){
                info.setCompany(c.getString(c.getColumnIndex("data1")));
            }else if("vnd.android.cursor.item/postal-address_v2".equals(mimetypes)){
                info.setAddress(c.getString(c.getColumnIndex("data1")));
            }
        }
        Toast.makeText(this, info.toString(), Toast.LENGTH_SHORT).show();
    }
}

添加联系人

/**
 * 添加联系人
 * @param view
 */
public void addContacts(View view){
    String name = et_name.getText().toString();
    String phone = et_phone.getText().toString();
    String email = et_email.getText().toString();
    String address = et_address.getText().toString();
    String company = et_company.getText().toString();


    //向raw_contact表中添加联系人个数
    ContentValues values = new ContentValues();
    Uri uri = getContentResolver().insert(uri_raw_contact, values);
    long id = ContentUris.parseId(uri);
    Cursor cursor = getContentResolver().query(uri_raw_contact, new String[]{"contact_id"}, "_id=?", new String[]{id + ""}, null);
    String contact_id = null;
    while(cursor.moveToNext()){
        contact_id = cursor.getString(cursor.getColumnIndex("contact_id"));
    }

    //添加联系人名称
    values.clear();
    values.put("mimetype","vnd.android.cursor.item/name");
    values.put("raw_contact_id",contact_id);
    values.put("data1",name);
    getContentResolver().insert(uri_data,values);

    //添加联系人手机号
    values.clear();
    values.put("mimetype","vnd.android.cursor.item/phone_v2");
    values.put("raw_contact_id",contact_id);
    values.put("data1",phone);
    getContentResolver().insert(uri_data,values);

    //添加联系人邮箱
    values.clear();
    values.put("mimetype","vnd.android.cursor.item/email_v2");
    values.put("raw_contact_id",contact_id);
    values.put("data1",email);
    getContentResolver().insert(uri_data,values);

    //添加联系人地址
    values.clear();
    values.put("mimetype","vnd.android.cursor.item/postal-address_v2");
    values.put("raw_contact_id",contact_id);
    values.put("data1",address);
    getContentResolver().insert(uri_data,values);

    //添加联系人公司
    values.clear();
    values.put("mimetype","vnd.android.cursor.item/organization");
    values.put("raw_contact_id",contact_id);
    values.put("data1",company);

    getContentResolver().insert(uri_data,values);
}

源码下载

https://github.com/zhangxun1900/learn_ipc_provider/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值