您的位置:首页 > 其它

安卓基础总结 内容提供者

2015-04-13 00:26 357 查看

1.使用内容提供者读写短信信息

(1)将短信内容读出并写入XML文件

API

ContentResolver contentResolver = getContentResolver();
//getContentResolver();是上下文中携带的方法,用于处理内容提供者提供的访问方式。


寻找哪个内容提供者需要用通过uri,uri路径分文 "主机名"+"具体要操作的数据"   其中"主机名"在提供数据库程序的清单文件中定义,"具体要操作的数据"在这个程序的源码中(一般文件名有provide字样),
我们可以通过查找"UriMatcher"函数搜索相关的信息。


读取短信例程

提供权限   读写短信  操作SD卡:
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

}

public void click(View v)
{
ContentResolver contentResolver = getContentResolver();

//通过查找TelephonyProvider程序的清单文件和源码可知,主机名为"sms" 后面为空则对应SMS_ALL
Uri uri = Uri.parse("content://sms/");

//使用ContentResolver提供的查询方法,查找短信相关信息
Cursor cursor = contentResolver.query(uri, new String[]{"address", "body"}, null, null, null);

//将cursor指向的内容封装到xml文件中
OutputStream os;
try {
os = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/msmInfo.xml");

XmlSerializer serializer = Xml.newSerializer();

serializer.setOutput(os, "utf-8");
serializer.startDocument("utf-8", true);

serializer.startTag(null, "info");

while(cursor.moveToNext())
{
serializer.startTag(null, "sms");

serializer.startTag(null, "address");
String address = cursor.getString(0);
serializer.text(address);
serializer.endTag(null, "address");

serializer.startTag(null, "body");
String body = cursor.getString(1);
serializer.text(body);
serializer.endTag(null, "body");

serializer.endTag(null, "sms");
}

serializer.endTag(null, "info");
serializer.endDocument();

} catch (Exception e) {
e.printStackTrace();
}

}
}


(2)将自定义信息写入短信程序下的数据库中

写入短信例程

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void click(View v)
{
ContentResolver contentResolver = getContentResolver();

Uri uri = Uri.parse("content://sms/");

//写入列名及其对应的值
ContentValues values = new ContentValues();
values.put("address", "110");
values.put("body", "hello chenchen");

contentResolver.insert(uri, values);
}
}


2.使用内容提供者读写联系人信息

背景知识

1.data表中存储联系人的所有信息
2.通过mimetype                    来区分信息对应的类型
3.通过raw_contact_id(即联系人的id)来区分不同信息对应的联系人


1.读取联系人信息模板 例程

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void click(View v)
{
ContentResolver contentResolver = getContentResolver();

//用于处理raw_contacts表格的uri
Uri uri_raw = Uri.parse("content://com.android.contacts/raw_contacts");

//用于处理data表格的uri
Uri uri_data = Uri.parse("content://com.android.contacts/data");

//查出raw_contacts表格中所有id号,也就是用户id
Cursor cursor = contentResolver.query(uri_raw, new String[]{"contact_id"}, null, null, null);

while(cursor.moveToNext())
{
//获得一个contact_id号
String contact_id = cursor.getString(0);

System.out.println("  contact_id:"+contact_id);

//查找data1表中所有contact_id为当前id的内容       ************注意此处为"mimetype"而不是直接写表中的"mimetype_id",此处是一个视图
Cursor cursor_data1 = contentResolver.query(uri_data, new String[]{"mimetype", "data1"}, "raw_contact_id=?", new String[]{contact_id}, null);

while(cursor_data1.moveToNext())
{
//查出当前行的mime类型,从而确定当前data1列的数据的类型
String mimetype = cursor_data1.getString(0);
System.out.println("*************mimetype*"+mimetype+"*****************");
String data = cursor_data1.getString(1);
System.out.println("*************data1*"+data+"*****************");

if("vnd.android.cursor.item/name".equals(mimetype)){
System.out.println("******name:"+data+"********");
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
System.out.println("******phone:"+data+"********");
}else if("vnd.android.cursor.item/email_v2".equals(mimetype)){
System.out.println("******email:"+data+"********");
}
}
}
}
}


将上述代码封装成一个工具类,用于获取联系人信息

public class ReadContactUtils {

/**
* 获取本机通讯录信息,返回通讯录中每个条目的List
* @param context   传入上下文,用于获取ContentResolver内容解析者
* @return
*/
public static List<Contact> getContacts(Context context)
{
List<Contact> list = new ArrayList<Contact>();
Contact contact=null;

ContentResolver contentResolver = context.getContentResolver();

Uri uri_raw = Uri.parse("content://com.android.contacts/raw_contacts");
Uri uri_data1 = Uri.parse("content://com.android.contacts/data");

Cursor cursor = contentResolver.query(uri_raw, new String[]{"contact_id"}, null, null, null);//由于要返回所有的条目,所以不需要写后面的参数

while(cursor.moveToNext())
{
//从raw_contact_id表中获取contact_id
String contact_id = cursor.getString(0);
//System.out.println("*******"+contact_id+"********");
if(contact_id != null)
{
contact = new Contact();

//使用contact_id查出data表中对应的所有对应项  ,这些对应项就是一个联系人的所有信息
Cursor cursor_data1 = contentResolver.query(uri_data1, new String[]{"mimetype", "data1"}, "raw_contact_id=?" ,new String[]{contact_id}, null);
while(cursor_data1.moveToNext())
{
//获取表的数据的类型
String mimetype = cursor_data1.getString(0);
String data1 = cursor_data1.getString(1);

//System.out.println("****mimetype*"+mimetype+"******data1*"+data1+"****");
//根据不同类型找到data1相应的位置
if("vnd.android.cursor.item/name".equals(mimetype)){
contact.setName(data1);
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
contact.setPhone(data1);
}else if("vnd.android.cursor.item/email_v2".equals(mimetype)){
contact.setEmail(data1);
}

}
}
list.add(contact);
}
return list;
}
}


2.写入联系人信息 例程

注意应当先在raw_contact_id表中加入新的contact_id,然后再添加data2中的各项信息。否则data2中不能插入信息。

public void click(View v)
{
String name = et_name.getText().toString().trim();
String email = et_email.getText().toString().trim();
String phone = et_phone.getText().toString().trim();

ContentResolver contentResolver = getContentResolver();

Uri uri_raw = Uri.parse("content://com.android.contacts/raw_contacts");
Uri uri_data1 = Uri.parse("content://com.android.contacts/data");

//看看raw_contact_id中的contact_id到第几条了
Cursor cursor = contentResolver.query(uri_raw, null, null, null, null);
int count = cursor.getCount();
int id = count+1;

//在raw_contact_id表中加入新信息的contact_id
ContentValues idValues = new ContentValues();
idValues.put("contact_id", id);
contentResolver.insert(uri_raw, idValues);

//分别加入信息中的每个行
ContentValues contentValues = new ContentValues();

contentValues.put("raw_contact_id", id);
contentValues.put("mimetype", "vnd.android.cursor.item/name");
contentValues.put("data1", name);
contentResolver.insert(uri_data1, contentValues);

contentValues.put("raw_contact_id", id);
contentValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
contentValues.put("data1", phone);
contentResolver.insert(uri_data1, contentValues);

contentValues.put("raw_contact_id", id);
contentValues.put("mimetype", "vnd.android.cursor.item/email_v2");
contentValues.put("data1", email);
contentResolver.insert(uri_data1, contentValues);
}


3.内容观察者ContentObserver

public class MainActivity extends Activity {

private Uri uri;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

uri = Uri.parse("content://sms");

//第二个参数的解释  为true可以是不精确的路径   为false必须是精确路径
//notifyForDescendents If true changes to URIs beginning with uri will also cause
//notifications to be sent. If false only changes to the exact URI specified by uri
//will cause notifications to be sent. If true, than any URI values at or below the
//specified URI will also trigger a match.

getContentResolver().registerContentObserver(uri, true, new MyObeserver(new Handler()));
}

class MyObeserver extends ContentObserver
{

public MyObeserver(Handler handler) {
super(handler);

}

//发现监视路径下的数据库发生变化就会调用此方法
@Override
public void onChange(boolean selfChange) {

//把短信的address 和  body内容取出来
Cursor cursor = getContentResolver().query(uri, new String[]{"address","body"}, null, null, "date desc");
cursor.moveToFirst();
String address = cursor.getString(0);
String body = cursor.getString(1);

System.out.println("body:"+body+"address:"+address);

super.onChange(selfChange);
}
}
}


4.内容提供者的原理简析

前几个条目主要说了我们如何获取其他数据的数据库信息,使用的是内容解析者提供的方法来对其他程序的数据库进行操作。

下面我们看一下数据库提供方程序是如何工作的。

1.同四大组件中其他的三个一样,也是继承一个类(ContentProvider),并为这个类在清单文件中配置一下。我们需要实现其中的增删改查方法。

public class MyContentProvider extends ContentProvider {

@Override
public boolean onCreate() {
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
}

@Override
public String getType(Uri uri) {

return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {

}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {

}
}

清单文件   name : 内容提供者的路径
authorities : 内容提供者的主机名

<provider android:name="com.example.readprivatedata.MyContentProvider"
android:authorities="com.example.myprovider">
</provider>

2.有了增删改查的方法,但是我们去操作哪站表,或者哪张表中的哪些数据呢?者就需要我们配置另外一个参数,用于找到对应的数据。我们使用**UriMatcher**类进行操作。

private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

//参数分别为   主机名   要操作的数据的标识   该标识对应的数字
matcher.addURI("com.example.myprovider", "info", INFO);

当我们进行增删改查操作时,从完整uri,通过match方法获取code码,每个code码对应操作不同的数据

int code = matcher.match(uri);获取当前uri对应的code码


例程

内容提供者

public class MyContentProvider extends ContentProvider {

//用于匹配调用哪个函数
private static final int INFO = 1;

private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private MyOpenHelper helper;

static{
//可以为matcher添加多个uri,用于操作不同的数据
matcher.addURI("com.example.myprovider", "info", INFO);
}

@Override
public boolean onCreate() {
//创建这个Provider时创建数据库,后面有这个类的源码   其中包含一张名为"info"的表格
helper = new MyOpenHelper(getContext());
return false;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {

//获取code码
int code = matcher.match(uri);

System.out.println("query******code:"+code+"*******");

//当code码和我们为某个数据预定义的code一样时,就进行对应的操作
if(code == INFO)
{
System.out.println("*******query********");

SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
return cursor;
}else {

throw new IllegalArgumentException("query路径不匹配 请检查");
}

}

@Override
public String getType(Uri uri) {

return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {

int code = matcher.match(uri);

System.out.println("insert******code:"+code+"*******");
if(code == INFO)
{
System.out.println("*******insert********");

//匹配成功
SQLiteDatabase db = helper.getReadableDatabase();
//代表插入到了多少行
long insert = db.insert("info", null, values);
return Uri.parse("com.itheima.account.provider"+insert);
}else {

throw new IllegalArgumentException("insert路径不匹配 请检查");
}

}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {

int code = matcher.match(uri);

System.out.println("delete******code:"+code+"*******");
if(code == INFO)
{
System.out.println("*******delete********");

SQLiteDatabase db = helper.getReadableDatabase();
int delete = db.delete("info", selection, selectionArgs);
//删除了多少行

return delete;
}else {
throw new IllegalArgumentException("3路径不匹配 请检查");

}
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {

int code = matcher.match(uri);

System.out.println(" update******code:"+code+"*******");
if(code == INFO)
{
System.out.println("*******update********");

SQLiteDatabase db = helper.getReadableDatabase();
int update = db.update("info", values, selection, selectionArgs);
//删除了多少行

return update;
}else {
throw new IllegalArgumentException("4路径不匹配 请检查");

}
}
}

创建数据库的类

public class MyOpenHelper extends SQLiteOpenHelper {

public MyOpenHelper(Context context) {
super(context, "account.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table info (_id integer primary key autoincrement,name varchar(20),money varchar(20))");
//初始化2条数据
db.execSQL("insert into info ('name','money') values ('张三','2000')");
db.execSQL("insert into info ('name','money') values ('李四','5000')");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

System.out.println("onUpgrade");
}
}


内容解析者

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void click_insert(View v)
{
ContentValues contentValues = new ContentValues();
contentValues.put("name", "haha");
contentValues.put("money", 10000);

//注意,uri决定了要操作的表,内容提供者在调用insert方法时,根据uri对应的code只找到相应的分支,这个分支对应的操作是操作info指定的数据
getContentResolver().insert(Uri.parse("content://com.example.myprovider/info"), contentValues);
}

public void click_delete(View v)
{
getContentResolver().delete(Uri.parse("content://com.example.myprovider/info"), "name=?", new String[]{"haha"});
}

public void click_update(View v)
{

}

public void click_find(View v)
{

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: