Android的四大组件之一,也是最后一个学习的四大组件,ContentProvider的作用是将Android程序的私有数据暴露给其他应用使用,可以自己选择暴露那些使用ContentProvider,一般来说暴露的都是数据库数据
-
首先要有一个类继承ContentProvider类,重写其中的方法,通关观察重写的方法可以发现,就是制定可以暴露的数据,通过增删改查方法的重写被别的程序调用
public class Provider extends ContentProvider { private Sqli sqli; private String table="aa"; @Override public boolean onCreate() { // TODO Auto-generated method stub sqli = new Sqli(getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub SQLiteDatabase database = sqli.getWritableDatabase(); Cursor cursor = database.query(table, null, selection, selectionArgs, null, null, null); return cursor; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub SQLiteDatabase database = sqli.getWritableDatabase(); database.insert(table, null, values); return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub SQLiteDatabase database = sqli.getWritableDatabase(); int delete = database.delete(table, selection, selectionArgs); return delete; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub SQLiteDatabase database = sqli.getWritableDatabase(); int update = database.update(table, values, selection, selectionArgs); return update; }
-
使用ContentProvider还必需在清单文件中进行注册
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.bch_5_22" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <--! 注册ContentProvider --> <provider android:name="com.example.pro.Provider" android:authorities="com.example.pro.Provider.aa" android:exported="true" > </provider> </application> </manifest>
android:name="com.example.pro.Provider"
确定使用的类的路径
android:authorities="com.example.pro.Provider.aa"
暴露的uri可以被其他程序调用的接口或者说网址
android:exported="true"
是否可以被其他程序调用
内容的解析者ContentResolver
有内容的提供者,就有使用它的东西,这就是内容的解析者ContentResolver,使用ContentProvider,需要两步。
resolver = getContentResolver();
uri = Uri.parse("content://com.example.pro.Provider.aa");
- 获取ContentResolver
- 获取uri
uri就是内容的提供者暴露的接口,
使用ContentResolver
通过ContentResolver和uri调用ContentProvider的方法获取数据。
package com.example.bch_ss;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private ContentResolver resolver;
private Uri uri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取内容解析者
resolver = getContentResolver();
// 指定Uri通过URI访问指定的内容提供者
uri = Uri.parse("content://com.example.privoide.mycompany");
}
public void add(View view) {
ContentValues values = new ContentValues();
values.put("name", "小舅子");
values.put("emp", "经理");
resolver.insert(uri, values);
}
public void find(View view) {
Cursor cursor = resolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
Log.i("aaa",
"姓名:" + cursor.getString(cursor.getColumnIndex("name"))
+ "职位:"
+ cursor.getString(cursor.getColumnIndex("emp")));
}
}
public void updata(View view) {
// update company set emp = "" where name = ?
ContentValues values = new ContentValues();
values.put("emp", "老司机");
int update = resolver.update(uri, values, "name=?",
new String[] { "张三" });
if (update > 0) {
Toast.makeText(MainActivity.this, "修改成功", 0).show();
}
}
public void del(View view) {
// delete from company where name = ?
int delete = resolver.delete(uri, "name=?", new String[] { "小舅子" });
if (delete > 0) {
Toast.makeText(MainActivity.this, "删除成功", 0).show();
}
}
}
系统提供的ContentProvider
实际上,Android系统为开发者提供了大量的ContentProvider,例如短信信息、联系人信息、系统的多媒体信息等,开发者自己开发的APP也可以通过ContentResolver来间接调用系统提供的ContentProvider所实现的insert()
、delete()
、update()
、query()
方法,这样开发者就可以获取到Android内部数据了。
获取联系人
Android系统提供了Contacts应用程序(com.android.providers.contacts)来管理联系人,也为联系人管理提供了相应的ContentProvider,其他应用程序同样可以通过ContentResolver访问管理联系人的ContentProvider,间接操作联系人数据库contacts2.db,即可实现管理联系人。
下面列出了管理联系人主要涉及的联系人数据库中的三张表,以及表中需要关注的字段:
- raw_contacts表
- contact_id:联系人ID
- data表:保存联系人的详细信息,一条信息占一行,而不是一个联系人占一行
- data1:联系人信息的具体内容
- raw_contact_id:联系人ID,标识该条信息属于哪个联系人
- mimetype_id:标识该条信息属于什么MIME类型
- mimetypes表:保存各个mimetype_id对应的MIME类型(姓名、号码、邮箱...)
下面的代码简单的实现了获取全部联系人到JavaBean并输出
ContentResolver resolver = getContentResolver();
// 先查询raw_contacts表获取所有联系人ID(/raw_contacts表示查询raw_contacts表)
Cursor cursorContactId =
resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},
null, null, null);
while (cursorContactId.moveToNext()) {
String contactId = cursorContactId.getString(0);
// 使用联系人ID作为where条件去查询属于该联系人的信息(/data实际上是多张表的复合查询)
Cursor cursorContactInfo = resolver.query(Uri.parse("content://com.android.contacts/data"),
new String[]{"data1", "mimetype"},
"raw_contact_id = ?",
new String[]{contactId},
null);
ContactBean contact = new ContactBean(); // 联系人JavaBean
while (cursorContactInfo.moveToNext()) {
String data1 = cursorContactInfo.getString(0);
String mimeType = cursorContactInfo.getString(1);
switch (mimeType) { // 根据不同的MIME类型把联系人信息保存到JavaBean
case "vnd.android.cursor.item/name":
contact.setName(data1);
break;
case "vnd.android.cursor.item/phone_v2":
contact.setPhone(data1);
break;
case "vnd.android.cursor.item/email_v2":
contact.setEmail(data1);
break;
default:
break;
}
System.out.println(contact);
}
}
不要忘记在清单文件中注册读联系人权限
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
添加联系人
添加联系人,只需要向上面的三张表中插入新联系人的数据。
向raw_contacts表中插入新联系人的contact_id之前,需要先遍历这个表,以确定新联系人的contact_id是多少,注意这里不应该用已有的contact_id(如果用户删除了某个联系人,这个字段会置空)来确定新联系人的contact_id,只能依据主键_id来确定。新联系人的contact_id插入完成之后,我们就可以插入具体的联系人信息。
该过程的完整的代码如下:
ContentResolver resolver = getContentResolver();
// 先查询目前最新的联系人的主键_id,新联系人的ID在此基础上加1即可得到
Cursor cursorId = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"_id"},
null, null, null);
int _id = 0;
if (cursorId.moveToLast()) {
_id = cursorId.getInt(0);
}
int contactId = _id + 1;
// 向raw_contacts表中插入新联系人ID
ContentValues contentValues = new ContentValues();
contentValues.put("contact_id", contactId);
resolver.insert(Uri.parse("content://com.android.contacts/raw_contacts"), contentValues);
// 插入具体的联系人信息
// 插入名字
contentValues.clear();
contentValues.put("raw_contact_id", contactId);
contentValues.put("data1", et_name.getText().toString());
contentValues.put("mimetype", "vnd.android.cursor.item/name");
resolver.insert(Uri.parse("content://com.android.contacts/data"), contentValues);
// 插入号码
contentValues.clear();
contentValues.put("raw_contact_id", contactId);
contentValues.put("data1", et_phone.getText().toString());
contentValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
resolver.insert(Uri.parse("content://com.android.contacts/data"), contentValues);
这里需要在清单文件中注册读联系人权限和写联系人权限
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
<uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>