内容提供者ContentProvider
- 案例-内容提供者,内容解析者
- 案例-操作系统短信
- 案例-操作系统联系人
- 案例-内容观察者
案例-内容提供者,内容解析者
- 概念:
- 将本app的数据库中的数据,提供给为外部应用访问(对外提供一个url地址)
- 创建一个内容提供者
- 在清单文件中注册
<provider
android:name="com.example.contentprovicer.ContentProvicer"
android:authorities="com.example.contentprovicer"
android:exported="true" >
</provider>
- 方法:
- onCreate():
- 当应用启动时,被回调,用于初始化数据库访问的工具
- 返回返回值是boolean,TRUE为初始化完成,FALSE说明有问题
数据库创建
- 创建一个类去继承SQLIiteOpenHerlper类
onCreate():
- 创建一个数据可子类的对象
- 初始化数据库内容
- 获取context对象调用getContext()
- insert():返回值URI
- 参数一和参数二正是内容解析者ContentResolver的参数
- 插入数据
- 创建一个数据库database调用getWriteableDatabase();
- 拼接行号,调用工具类,ContentUris
Uri withAppendedId = ContentUris.withAppendedId(uri, insert);
- 匹配不同表名
- 调用UriMatcher类去添加uri地址
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- 创建一个内容解析者工程
- 在MainActivity中
- 获取 内容解析者 调用 getContentResolver()
- 调用内容解析者的CRUD方法
- 用内容解析者调用 insert(url,values),query(),delete(),update();
- 参数1:url,用找到内容提供者,获取方法Uri.parse(String 地址值);
- 参数2:要添加数据
==注意,在内容提供者在查询时,先不要关闭数据库和cursor,因为他要接收解析者穿过来得数据,谁用谁在关闭就行==
这里放insert方法的代码
- 内容提供者
private static final UriMatcher uriMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
private static final int TABLE_MAN = 1;
private static final int TABLE_WMAN = 2;
static {
/*
* addURI(); 参数一:APP主机地址 参数二:表名 参数三:各个拼接好的地址对应的常量值
*/
uriMatcher.addURI("com.example.contentprovicer", "t_man", TABLE_MAN);
uriMatcher.addURI("com.example.contentprovicer", "t_wman", TABLE_WMAN);
}
@Override
public boolean onCreate() {
Context context = getContext();
userSQLiteOpenHenpler = new UserSQLiteOpenHenpler(context, DB_NAME,
null, VERSION);
return true;// 返回true代表初始化完成
}
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.d("tag", uri.toString());
// 获取封装地址对应的码数,也就是addURI的第三个参数
String tableName = getTableName(uri);
SQLiteDatabase database = userSQLiteOpenHenpler.getReadableDatabase();
long insert = database.insert(tableName, null, values);
// 字符串拼接把地址和行号拼接起来,然后返回到内容解析者中,返回插入的第几行
Uri withAppendedId = ContentUris.withAppendedId(uri, insert);
database.close();
return withAppendedId;
}
private String getTableName(Uri uri) {
String tableName = "";
int match = uriMatcher.match(uri);
switch (match) {
case TABLE_MAN:
tableName = "t_man";
break;
case TABLE_WMAN:
tableName = "t_wman";
break;
default:
break;
}
return tableName;
}
- 解析者
public void insertMan(View view) {
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("t_name", "hhh");
values.put("t_age", 11 + new Random().nextInt(100));
values.put("t_phone", "1234567412");
// insert返回类型是uri
Uri insert = contentResolver.insert(
Uri.parse("content://com.example.contentprovicer/t_man"),
values);
// 调用ContentUris.parseId(insert);,把主机地址的id解析出来
long parseId = ContentUris.parseId(insert);
Toast.makeText(this, "在" + parseId + "插入成功", Toast.LENGTH_SHORT).show();
}
- 案例-操作系统短信
- 创建UI,
- 创建一个button获取短信
- 创建一个listview放短信内容
- 在MainActivity里初始化UI
观察系统短信数据库,看看怎么写什么数据
- 获取内容解析者
- 内容借解析者调用query();
- 看源码需要什么权限,以及主机名是什么
- 主机名 sms
- 添加权限
<uses-permission android:name="android.permission.READ_SMS"/>
- 创建一个类包含数据库的内容
- 把查询内容添加到List<..>
- 把内容添加到adapter中调用arrayadapter(),给listview设置布局
``` public void getsms(View view) { List<Sms> lSms = new ArrayList<Sms>(); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(Uri.parse("content://sms"), new String[] { "address,date,type,body" }, null, null, null); while (cursor.moveToNext()) { Sms sms = new Sms(); sms.setAddress(cursor.getString(0)); sms.setDate(cursor.getString(1)); sms.setType(cursor.getInt(2)); sms.setBody(cursor.getString(3)); lSms.add(sms); } cursor.close(); smsView.setAdapter(new ArrayAdapter<Sms>(MainActivity.this, android.R.layout.simple_list_item_1, lSms)); } ```
插入短信
- 创建一个UI两个edittext和一个button
- 初始化UI
- 插入
拿到解析者,调用insert
“`
public void insertSms(View view) {
String phone = ed_Phone.getText().toString().trim();
String sms = ed_Sms.getText().toString().trim();ContentResolver resolver = getContentResolver(); ContentValues values = new ContentValues(); values.put("address", phone);
// 设置当前时间
values.put(“date”,getDataString(new Date().getTime()));
values.put(“type”, “1”);
values.put(“body”, sms);
Uri insert = resolver.insert(Uri.parse(“content://sms”), values);
Log.d(“tag”, insert.toString());
long parseId = ContentUris.parseId(insert);
Toast.makeText(this, “插入成功:”+parseId, Toast.LENGTH_SHORT).show();}
- 解析时间
private String getDataString(long data) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date(data));
}
获取URI(uri.parse()),values
添加权限
<uses-permission android:name="android.permission.WRITE_SMS"/>
案例-操作系统联系人
步骤:
查询联系人
- 创建两个button,和一个listView,用来获取查询的联系人
- 创建一个工具类,用来放联系人的姓名,电话,以及邮箱,以及地址
- 查看安卓数据库,看需要什么(一共需要3个表,一个存放id,一个存放信息data.一个用来存放信息类型mimetype)
- 需要添加权限
//读取联系人的权限 <uses-permission android:name="android.permission.READ_CONTACTS" /> //添加联系人的权限 <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- 获取内容解析者
-
- 查询raw_contacts表,遍历contact_id,当遍历到cotnact_id = 1;
-
- 查询data表,遍历所有contact_id =
1的数据。然后根据数据的mimeType确定这个数据是什么字段,然后封装到当前javaBean的字段上
- 注意:表名必须是data,但是其底层走的是视图
- (view_data),因此要查询的mimetype_id字段已经映射为mimetype了
- 注意:同上理,raw_contact_id写成contact_id即可 根据id去查找存储的类型以及信息
- 查询data表,遍历所有contact_id =
- // 最后把获取id的结果集关闭
- 把获取的内容部署到listview上
public void getContact(View view) { ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query( Uri.parse("contant://com.android.contacts/raw_contacts"), new String[] { "contant_id" }, "delete=?", new String[] { "0" }, null); while (cursor.moveToNext()) { // 每遍历一次就会创建一个新的对象,因为在安卓系统源码中是分类存放的,id一个,不同的信息一个 Contacts contacts = new Contacts(); int id = cursor.getInt(0); /** * 2. 查询data表,遍历所有contact_id = * 1的数据。然后根据数据的mimeType确定这个数据是什么字段,然后封装到当前javaBean的字段上 * 注意:表名必须是data,但是其底层走的是视图 * (view_data),因此要查询的mimetype_id字段已经映射为mimetype了 * 注意:同上理,raw_contact_id写成contact_id即可 *根据id去查找存储的类型以及信息 */ Cursor dataCursor = contentResolver.query( Uri.parse("contant://com.android.contacts/data"), new String[] { "mimetype", "data1" }, "id=?", new String[] { "" + id }, null); while (dataCursor.moveToNext()) { String type = dataCursor.getString(0); String data1 = dataCursor.getString(1); switch (type) { case "vnd.android.cursor.item/name": contacts.name = data1; break; case "vnd.android.cursor.item/email_v2": contacts.phone = data1; break; case "vnd.android.cursor.item/postal-address_v2": contacts.email = data1; break; case "vnd.android.cursor.item/phone_v2": contacts.address = data1; break; default: break; } dataCursor.close(); list.add(contacts); } // 最后把获取id的结果集关闭 cursor.close(); lView.setAdapter(new ArrayAdapter<Contacts>(this, android.R.layout.simple_expandable_list_item_1, list)); } }
添加联系人
步骤:
- 获取内容解析者,调用getContactResolver()
- 先在id表中(rew_contact_id)查询最大的id,调用query(),查询的uri是rew_contact_id,查询完要记得关闭结果集cursor
- 用来确定要插入的id数,用最大id加一,就是要插入的id数
- 添加要添加数据
- 创建JavaBean的对象,设置要添加数据
- 用内容解析者调用insert(),插入的uri是data
- 插入name
- 清空values
- 插入phone
- 清空values
- 插入email
- 清空values
- 插入address
- 最后弹吐司,告诉用户添加完成
“`
public void insertContacts(View view) {
Contacts contacts = new Contacts();
contacts.name = “徐嘉”;
contacts.address = “江苏南京雨花台区前门大街118号”;
contacts.email = “888888888@qq.com”;
contacts.phone = “1383838383838”;
/**-
- 先往raw_contacts表中插入contact_id (1). 先读取当前最大的contact_id (2).
- contact_id+1 得到新的id
-
*/
ContentResolver resolver = getContentResolver();
int new_contact_id = 1;
Cursor cursor = resolver.query(Uri.parse(“content://com.android.contacts/raw_contacts”),
new String[]{“contact_id”}, null, null, “contact_id desc limit 1”);
if (cursor.moveToNext()) {
int contact_id = cursor.getInt(0);
new_contact_id = contact_id+1;
}
cursor.close();
ContentValues values = new ContentValues();
values.put(“contact_id”, new_contact_id);
resolver.insert(Uri.parse(“content://com.android.contacts/raw_contacts”), values);/*
-
- 往data表中插入name,data是视图表 出入rew_contacts_id 插入mimetype 插入name 内容
*/
values.clear();
values.put(“raw_contact_id”, new_contact_id);
values.put(“data1”, contacts.name);
values.put(“mimetype”, “vnd.android.cursor.item/name”);
resolver.insert(Uri.parse(“content://com.android.contacts/data”), values);
- 往data表中插入name,data是视图表 出入rew_contacts_id 插入mimetype 插入name 内容
// 插入phone
values.clear();
values.put(“raw_contact_id”, new_contact_id);
values.put(“data1”, contacts.phone);
values.put(“mimetype”, “vnd.android.cursor.item/phone_v2”);
resolver.insert(Uri.parse(“content://com.android.contacts/data”), values);/**
-
- 插入email
*/
values.clear();
values.put(“raw_contact_id”, new_contact_id);
values.put(“data1”, contacts.email);
values.put(“mimetype”, “vnd.android.cursor.item/email_v2”);
resolver.insert(Uri.parse(“content://com.android.contacts/data”), values);
/**
- 插入email
-
- 插入address
*/
values.clear();
values.put(“raw_contact_id”, new_contact_id);
values.put(“data1”, contacts.address);
values.put(“mimetype”, “vnd.android.cursor.item/postal-address_v2”);
resolver.insert(Uri.parse(“content://com.android.contacts/data”), values);
- 插入address
Toast.makeText(this, “插入完毕”, Toast.LENGTH_SHORT).show();
}
}
“`
案例-内容观察者
步骤:
在onCreate()方法中注册内容观察者用内容解析者调用registerContentObserver()
mContentObsever = new MyContentObsever(new Handler());//这个是参数三的监听对象 getContentResolver().registerContentObserver(Uri.parse("contact://sms"), true, mContentObsever);
- 参数一:要观察的主机名
- 参数二:是否给派生的子uri也发出通知,再接收到短信给观察者发送通知
-参数三:监听对象,每次发送短信时都会回调监听对象里的onCHange()方法 - 创建监听对象的一个子类对象
// 创建内容观察第三个参数,回调方法的一个子类 class MyContentObsever extends ContentObserver { public MyContentObsever(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange,uri); Log.i("jjjj", uri.toString()); Toast.makeText(MainActivity.this, "观察到了信息的变化"+uri.toString(), Toast.LENGTH_LONG) .show(); } }
在onDestroy()取消观察者用内容解析者调用unregisterContentObserver()
@Override protected void onDestroy() { super.onDestroy(); // 取消内容观察者 if (mContentObsever != null) { getContentResolver().unregisterContentObserver(mContentObsever); mContentObsever = null; } }