Android四大组件之ContentProvider

    xiaoxiao2021-03-26  22

    要解决的问题:

    有两个工程A和工程B,工程A中通过SQLiteOpenHelper的子类创建了一个自产自销的数据库,工程B中没有数据库,但是工程B想要与工程A共用同一个数据库。

    为实现以上目标,需要2个系统类:

    ContentProvider 内容提供者 Andord四大组件之一ContentResolver 内容观察者 两者结合起来可以进程间(多个工程之间)数据的共享

    使用方式:

    工程A(要向其他工程开放数据的):

    先准备一个SQLiteOpenHelper的子类,用于管理当前工程自产自销的数据库为了把自产自销的数据库开放出去,需要通过ContentProvider进行以下操作: a. 创建一个ContentProvider的子类 b. 到清单文件中注册ContentProvider的子类 <!-- 在application标签中注册ContentProvider子类的信息 android:name 用于指定子类的具体路径 android:authorities 设置当前子类对应的作者名,属性值写任意字符串即可 用于稍后再其他工程中通过ContentResolver连接此类时,设置的Uri路径中的authorities android:exported="true" 允许进行数据开放操作 --> <provider android:name="com.example.day14_5_contentprovider.MyProvider" android:authorities="com.ay.sql" android:exported="true" ></provider>

    c. 在子类的增删改查方法中填写相应代码

    MyProvider子类:

    public class MyProvider ext ends ContentProvider { //初始化用于比较Uri路径类型的UriMatcher对象 private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int VIP = 1; private static final int VIP_ID = 3; private static final int VIP_LIKE = 4; private static final int BLACK = 2; static { //添加比对参照物 /** * 代表向matcher对象中存入参照物: content://com.ay.oye/vip , * 后期当通过matcher调用match方法进行比对时,一旦与当前参照物相同,match方法的返回值就是VIP对应的数据1 */ matcher.addURI("com.ay.oye", "vip", VIP); matcher.addURI("com.ay.oye", "black", BLACK); matcher.addURI("com.ay.oye", "vip/#", VIP_ID); //#代表任意数字 matcher.addURI("com.ay.oye", "vip/*", VIP_LIKE); //* 代表任意字符 } private SQLiteDatabase db; @Override public boolean onCreate() { // TODO Auto-generated method stub db = new MyHelper(getContext()).getReadableDatabase(); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub Cursor cursor = null; switch (matcher.match(uri)) { case VIP: //查询的是vip表 //通过db对象调用系统封装好数据库中用于实现查询的query方法 cursor = db.query("vip", projection, selection, selectionArgs, null, null, sortOrder); break; case BLACK: //查询的是black表 cursor = db.query("black", projection, selection, selectionArgs, null, null, sortOrder); break; case VIP_ID: if (selection == null) { cursor = db.query("vip", projection, "_id = "+uri.getLastPathSegment(), null, null, null, sortOrder); } else { cursor = db.query("vip", projection, selection+"and _id = "+uri.getLastPathSegment(), selectionArgs, null, null, sortOrder); } break; case VIP_LIKE: if (selection == null) { cursor = db.query("vip", projection, "name like ?", new String[] {"%"+uri.getLastPathSegment()+"%"}, null, null, sortOrder); } else { cursor = db.query("vip", projection, selection + " and name like "+"'"+"%"+uri.getLastPathSegment()+"%"+"'", selectionArgs, null, null, sortOrder); } break; } return cursor; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return matcher.match(uri)+""; } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub long num = 0; switch (matcher.match(uri)) { case VIP: num = db.insert("vip", "_id", values); break; case BLACK: num = db.insert("black", "_id", values); break; } return Uri.withAppendedPath(uri, num+""); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub switch (matcher.match(uri)) { case VIP: db.delete("vip", selection, selectionArgs); break; case BLACK: db.delete("black", selection, selectionArgs); break; case VIP_ID: if (selection == null) { db.delete("vip", "_id = "+uri.getLastPathSegment(), null); } else { db.delete("vip", selection+" and _id = "+uri.getLastPathSegment(), selectionArgs); } break; case VIP_LIKE: break; } return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } }

    工程B中(从工程A获取数据的):

    1. 初始化ContentResolver对象

    //初始化ContentResolver对象 cr = getContentResolver();

    2. 通过ContentResolver对象调用增删改查方法实现数据库操作 如:

    public void click (View v) { switch (v.getId()) { case R.id.but_add: /** * 先以增加为例 * 参数: * 1. Uri 用于描述路径 * 拼接特点: * scheme:// authorities / data * scheme 主题 ,代表当前路径的具体类型,即是一个文件路径还是一个电话等 * * 2.ContentValues ,用于存储要添加的数据 */ ContentValues values = new ContentValues(); values.put("name", "花花"); values.put("age", 28); /** * 执行流程: 根据Uri路径中的作者名在整个设备的所有应用中寻找,哪个ContentProvider的子类注册了 相同的作者名 * 找到后运行该子类中的insert方法 */ Uri uri = cr.insert(Uri.parse("content://com.ay.sql/pr"), values); //想要从insert方法的返回的uri对象中获取到新添加的数据对应的id值的话 String id = uri.getLastPathSegment(); Log.i("oye", "工程6 新添加数据对应的id为: : "+id); break; case R.id.but_query: /** * 参数: * 1. Uri路径 , * 2. 要查询表中的哪些列,填null代表获取所有列 * 3, 查询的条件 * 3, 用于替换条件中?的值 * 5. 排序 */ Cursor cursor = cr.query(Uri.parse("content://com.ay.sql/pr"), null, null, null, null); while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); Log.i("oye", "工程6中获取到的数据位: "+name); } break; case R.id.but_delete: int num = cr.delete(Uri.parse("content://com.ay.sql/pr"), "_id=?", new String[]{"3"}); Log.i("oye", "工程6中删除的条数为:"+num); break; case R.id.but_update: ContentValues cv = new ContentValues(); cv.put("name", "王老六"); int num1 = cr.update(Uri.parse("content://com.ay.sql/pr"), cv, "_id = ?", new String[]{"5"}); Log.i("oye", "工程6中删除的条数为:"+num1); break; } }

    相对来说常见的使用如 :

    系统的通话记录工程通过ContentProvider将通话记录开放了出来,我们想要获取通过记录信息,只需通过ContentResolver调用相应的增删改查方法即可

    通过ContentResolver读取常见的系统数据:

    1. 通话记录信息 2. 短信记录信息 3. 联系人通讯录信息

    一、通过ContentResolver读取通话记录:

    读取前的准备: 确保用于测试的设备上有通话记录,否则读取不出内容

    如果是模拟器处理通话记录的方式:

    1.拨出电话: 直接使用模拟器上的拨号软件即可 2.接听电话 (只有原生模拟器可以模拟接听电话):选择打开Window—ShowVIew --- Other—Android中的Emulator Control标签,在此标签中可以实现向模拟器中拨出电话,发出短信的功能

    系统通话记录表的存储位置:

    /* * 通话记录的数据库的位置:data/data/com.android.providers.contacts/databases/contacts2.db * 表名为:calls * 对应的作者名:call_log * 通过query方法读取内容 */

    通话记录表中的主要列:

    number 存储电话号 type 存储通话类型,1 代表来电(接听的电话) 2 代表去电(拨出的电话) date 通话的日期 duration 通话的持续时长

    连接通过记录使用的Uri:

    Uri.parse("content://call_log/calls")

    具体的读取方式:

    Cursor cursor = cr.query(Uri.parse("content://call_log/calls"), null, null, null, null); while(cursor.moveToNext()) { //电话号码 String number = cursor.getString(cursor.getColumnIndex("number")); //是来电还是去电 String s = cursor.getString(cursor.getColumnIndex("type")); String type = s.equals("1") ? "来电(接听的电话)":"去电(拨出的电话)"; //时间 String date = cursor.getString(cursor.getColumnIndex("date")); //获取通话时长 String duration = cursor.getString(cursor.getColumnIndex("duration")); Log.i("oye", "通过话记录中的数据位: "+number +" "+date+" "+type+" "+duration); }

    需要添加的权限:

    <!-- 添加读取通话记录的权限 --> <uses-permission android:name="android.permission.READ_CALL_LOG"/> <!-- 添加修改写入通话记录的权限 --> <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

    二、通过ContentResolver读取短信记录:

    系统短信记录表的存储位置:

    data/data/com.android.provider.telephony/databases/mmssms.db中的sms表

    连接使用的Uri:

    content://sms

    表中比较重要的列:

    address 电话号码 date 接收短信的日期 date_sent 发送短信的日期 read 用于标识短信是否已读, 0代表未读,1代表已读 type 用于标识短信类型 1 接收的短信,2发送的短信 3 发送失败,在草稿箱的短信 body 短信内容

    读取方式:

    protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); ContentResolver cr = getContentResolver(); Cursor cursor = cr.query(Uri.parse("content://sms"), null, null, null, null); while (cursor.moveToNext()) { String number = cursor.getString(cursor.getColumnIndex("address")); String mess = cursor.getString(cursor.getColumnIndex("body")); String read = cursor.getString(cursor.getColumnIndex("read")).equals("0") ? "未读":"已读"; String type = cursor.getString(cursor.getColumnIndex("type")).equals("1")?"接收的短信":"发送的短信"; Log.i("oye", "获取到的短信内容为: "+number+" "+mess+" "+read+" "+type); } }

    需要的权限:

    <!-- 读取短信记录的权限 --> <uses-permission android:name="android.permission.READ_SMS"/> <!-- 修改短信记录的权限 --> <uses-permission android:name="android.permission.WRITE_SMS"/>

    三、通过ContentResolver读取系统通讯录联系人

    系统通讯录联系人表的存储位置:

    data/data/com.android.providers.contacts/databases/Contacts2.db的数据库文件中

    读取联系人信息的主要表:

    1.raw_contacts 用于存储联系人的名字以及该联系人对应的唯一id值 2.data 用于存储所有联系人的所有数据,但是注意: (1)一行中并没有存储一个联系人的所有信息 而是将一个联系人的所有信息拆分成了多行存储 判断哪几行数据是属于同一个联系人的方式为: 根据每一行的raw_contact_id的值判断,值相同的则为同一联系人的所有数据 (2)基本上大部分的数据都是存储在data1列中,为了判断本行data1中的数据属于哪种类型(是电话号码还是姓名),需要根据mimetype_id这一列中的值进行判断 3.Mimetypes 用于存储所有的数据类名,如:电话号,姓名,邮箱地址等

    读取方式:

    读取方式一:

    private ArrayList<MyC> queryAll() { ArrayList<MyC> list = new ArrayList<MyC>(); // 1. 读取raw_contacts这张表,目的:获取每一个人联系人的唯一id标识,本次得到的idCursor中存储了所有联系人id值 Cursor idCursor = cr.query( Uri.parse("content://com.android.contacts/raw_contacts"), null, "deleted = 0", null, null); while (idCursor.moveToNext()) { // 获取联系人的id int id = idCursor.getInt(idCursor.getColumnIndex("_id")); MyC myc = new MyC(); myc.setId(id); // 2. 根据或得到的id值到data表中读取数据,本次得到的cursor对象中存储了一个联系人的多方面数据 Cursor cursor = cr.query( Uri.parse("content://com.android.contacts/data"), null, "raw_contact_id = " + id, null, null); // 3. 循环cursor对象,读取联系人数据 while (cursor.moveToNext()) { // 获取data1这一列的值 String data1 = cursor.getString(cursor.getColumnIndex("data1")); Log.i("oye", "当前行中data1 的数据为: " + data1); String mime = cursor.getString(cursor .getColumnIndex("mimetype")); if (mime.equals("vnd.android.cursor.item/name")) { // 代表当前行的data1列中存储的是姓名 myc.setName(data1); } else if (mime.equals("vnd.android.cursor.item/email_v2")) { // 代表本行的data1中存储的是邮箱地址 myc.setEmail(data1); } else if (mime .equals("vnd.android.cursor.item/postal-address_v2")) { // 家庭住址 myc.setAddress(data1); } else if (mime.equals("vnd.android.cursor.item/phone_v2")) { // 存储的是电话号 String data2 = cursor.getString(cursor .getColumnIndex("data2")); if (data2.equals("1")) { // 家庭座机号 myc.setPhone_home(data1); } else if (data2.equals("2")) { // 手机号 myc.setPhone_mobile(data1); } } } list.add(myc); Log.i("oye", "*************************************"); } return list; }

    读取方式二:

    public void queryAllMethod2() { // 管理所有联系人的Uri Cursor c1 = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); //读取所有联系人的名字 while (c1.moveToNext()) { String name = c1.getString(c1 .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); Log.i("oye", "c1 ddd " + c1.toString() + " " + name); } Cursor c2 = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); //读取所有的联系人的电话号 while (c2.moveToNext()) { String number = c2.getString(c2 .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); Log.i("oye", "c1 ddd " + c2.toString() + " " + number); } }

    需要添加的权限:

    <!-- 读取通讯录联系人的权限 --> <uses-permission android:name="android.permission.READ_CONTACTS"/> <!-- 修改,添加通讯录联系人的权限 --> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

    删除数据的方式:

    case R.id.but_delete: //删除通讯录中联系人 //1. 从raw_contacts表中删除数据 cr.delete(Uri.parse("content://com.android.contacts/raw_contacts"), "_id=2", null); //2. (可不写)再到data表中删除联系人 cr.delete(Uri.parse("content://com.android.contacts/data"), "raw_contact_id = 2", null); break;

    新增数据的方式:

    case R.id.but_insert: //新增联系人数据 //1.先向raw_contacts表中存入数据,并获取新添加的数据对应的id值 ContentValues values = new ContentValues(); values.put("display_name", "小赵"); Uri uri = cr.insert(Uri.parse("content://com.android.contacts/raw_contacts"), values); //获取新添加的数据对应的id值 String id = uri.getLastPathSegment(); //2. 根据id向data表中分别存入,姓名,邮箱,电话号的信息 //存入姓名信息 values.clear(); values.put("data1", "小赵"); values.put("raw_contact_id", id); values.put("mimetype", "vnd.android.cursor.item/name"); cr.insert(Uri.parse("content://com.android.contacts/data"), values); //存入邮箱信息 values.clear(); values.put("data1", "250@250.com"); values.put("raw_contact_id", id); values.put("mimetype", "vnd.android.cursor.item/email_v2"); values.put("data2", "1"); cr.insert(Uri.parse("content://com.android.contacts/data"), values); //存入电话号码信息 values.clear(); values.put("data1", "250250250"); values.put("raw_contact_id", id); values.put("mimetype", "vnd.android.cursor.item/phone_v2"); values.put("data2", "2"); cr.insert(Uri.parse("content://com.android.contacts/data"), values); break;

    修改数据的方式:

    case R.id.but_update: //修改联系人 //修改数据库中的原有内容 ContentValues values2 = new ContentValues(); values2.put("data1", "252252252"); cr.update(Uri.parse("content://com.android.contacts/data"), values2, "raw_contact_id = ? and mimetype = ?", new String[]{"3","vnd.android.cursor.item/phone_v2"}); //向数据库中添加新内容 ContentValues values1 = new ContentValues(); values1.put("data1", "家庭住址:"); values1.put("raw_contact_id", 3); values1.put("mimetype", "vnd.android.cursor.item/postal-address_v2"); cr.insert(Uri.parse("content://com.android.contacts/data"), values1); break;
    转载请注明原文地址: https://ju.6miu.com/read-658903.html

    最新回复(0)