内容提供者
01_为什么需要内容提供者
为了能够让其他应用程序访问本地应用程序中数据库,使用内容提供者对外开放几个接口,让其他应用程
序调用这些接口。
02_编写内容提供者(重点)
步骤:
1、在工程中添加一个内容提供者的类,继承ContentProvider,重写其中的方法;
2、在配置文件中配置一个provider,指定主机名唯一标示内容提供者(android4.1.2之后的版本中,需要指定exported=true,否则其他应程序没有权限访问该内容提供者);
3、在内容提供者类里面,创建一个uriMather(柜员),然后做岗前培训,添加增删改查的uri;
4、在内容提供者的增删改查的方法判断uri是否匹配正确,再调用数据库的增删改查的方法访问数据库;
03_内容提供者工作的原理(重点)
在其他应用程序中,通过内容提供者的解析器,操作内容提供者。
通过一个uri唯一的匹配内容提供者,在uri中指定了操作的路径(内容提供者已经匹配过的路径),内容提供者接收到这个uri后就可以做相应的操作;
uri url
http://www.baidu.com:80/i.html
content
ftp://
uri组成:schemel,主机名、端口、路径
http://www.baidu.com/i.html
content://com.itheima.dbapp.accountcontentprovider/delete
04_内容提供者的增删改查的实现
代码:
package com.itheima.dbapp;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class AccountContentProvider extends ContentProvider {
private AccountDBHelper helper;
private static String INSERT = "insert";
private static String DELETE = "delete";
private static String UPDATE = "update";
private static String QUERY = "query";
//创建一个银行的柜员
private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//柜员的岗前培训
static{
// content://com.itheima.dbapp.accountcontentprovider/insert
// content://com.itheima.dbapp.accountcontentprovider/delete
mUriMatcher.addURI("com.itheima.dbapp.accountcontentprovider", INSERT, 1);
mUriMatcher.addURI("com.itheima.dbapp.accountcontentprovider", DELETE, 2);**
mUriMatcher.addURI("com.itheima.dbapp.accountcontentprovider", UPDATE, 3);
mUriMatcher.addURI("com.itheima.dbapp.accountcontentprovider", QUERY, 4);
}
/**
* 初始化实例对象
* 通常是创建一个数据库帮助类的对象
*/
@Override
public boolean onCreate(){
helper = new AccountDBHelper(getContext());
return false;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//匹配用户的相应操作,匹配码与柜员培训的匹配吗一致
if(mUriMatcher.match(uri) == 1){
SQLiteDatabase db = helper.getWritableDatabase();
db.insert("account", null, values);
}
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
if(mUriMatcher.match(uri) == 4){
SQLiteDatabase db = helper.getWritableDatabase();
return db.query("account", projection, selection, selectionArgs, null, null, sortOrder);
}else{
return null;
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
if(mUriMatcher.match(uri) == 3){
SQLiteDatabase db = helper.getWritableDatabase();
db.update("account", values, selection, selectionArgs);
}
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
if(mUriMatcher.match(uri) == 2){
SQLiteDatabase db = helper.getWritableDatabase();
db.delete("account", selection, selectionArgs);
}
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
}
05_内容提供者的使用场景
场景:
写内容提供者的场景:让其他应用程序访问自己应用程序数据库中的数据;
写内容提供者的解析器场景:访问别的应用程序中的内容提供者时;
06_插入短信(重点)
在自己的工程里访问手机上短信应用程序里面短信列表。
1、需要访问短信应用提供的内容提供者;
2、需要知道uri:content://sms/;
3、分析数据库表:sms;address,date,type,body;
代码:
package com.itheima.insertsms;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void insert(View view){
//得到内容提供者的解析器
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
ContentValues values = new ContentValues();
values.put("address", "18910903535");
values.put("date",System.currentTimeMillis());
values.put("type", 1);//type为表示接收到短信
values.put("body", "上次从我这里借的500万还没还我呢");
resolver.insert(uri, values);
Toast.makeText(this, "插入完成", 0).show();
}
}
07_内容提供者uri的写法
content://sms/;
1、需要访问短信应用提供的内容提供者;
2、需要知道uri:content://sms/;
3、分析数据库表:sms;address,date,type,body;
08_短信的备份(重点)
第一步:通过内容提供者查询短信列表:
1、需要访问短信应用提供的内容提供者;
2、需要知道uri:content://sms/;
3、分析数据库表:sms;address,date,type,body;
第二步:把短信列表序列化到xml的文件上:
4、把备份的文件写到SD卡上;
5、使用xml格式的文件存数短信;
代码:
package com.itheima.copysms;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void backup(View view){
try {
//1、访问短信应用的内容提供者
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, null, null, "date desc");
//得到xml序列化器
XmlSerializer s = Xml.newSerializer();
FileOutputStream os = new FileOutputStream(new File(Environment.getExternalStorageDirectory()+"/backup.xml"));
//初始化序列器
s.setOutput(os, "UTF-8");
s.startDocument("UTF-8", true);
s.startTag(null, "info");
while(cursor.moveToNext()){
String address = cursor.getString(0);
long date = cursor.getLong(1);
int type = cursor.getInt(2);
String body = cursor.getString(3);
s.startTag(null, "sms");
s.startTag(null, "address");
s.text(address);
s.endTag(null, "address");
s.startTag(null, "date");
s.text(date+"");
s.endTag(null, "date");
s.startTag(null, "type");
s.text(type+"");
s.endTag(null, "type");
s.startTag(null, "body");
s.text(body);
s.endTag(null, "body");
s.endTag(null, "sms");
}
s.endTag(null, "info");
s.endDocument();
cursor.close();
os.close();
Toast.makeText(this, "备份成功", 0).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
09_短信的还原操作(重点)
把已经备份的xml短信数据插入到短信应用的数据库表中。
1、解析xml的短信数据:
2、通过短信应用程序的内容提供者把数据插入到数据库表中:
代码:
package com.itheima.restoresms;
import java.io.File;
import java.io.FileInputStream;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;
import android.widget.Toast;
import com.itheima.restoresms.domain.SmsInfo;
public class MainActivity extends Activity {
private SmsInfo sms;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void restore(View view) {
// 创建一个对话框的构造器
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("提醒");
builder.setMessage("是否删除所有短信并重新还原?");
builder.setPositiveButton("是", new OnClickListener() {
/**
* 单击按钮时调用这个方法
*/
@Override
public void onClick(DialogInterface dialog, int which) {
//删除短信
deleteSms();
//还原短信
insertSms();
}
});
builder.setNegativeButton("否", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
// 使用构造器创建出一个对话框对象
AlertDialog ad = builder.create();
ad.show();
}
public void insertSms() {
try {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
resolver.delete(uri, null, null);
// 解析xml文件
XmlPullParser parser = Xml.newPullParser();
FileInputStream fis = new FileInputStream(new File(
Environment.getExternalStorageDirectory() + "/backup.xml"));
parser.setInput(fis, "UTF-8");
// 得到解析的事件类型
int type = parser.getEventType();
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
case XmlPullParser.START_TAG:// 开始标签的事件类型
if ("sms".equals(parser.getName())) {
sms = new SmsInfo();
} else if ("address".equals(parser.getName())) {
String address = parser.nextText();
sms.setAddress(address);
} else if ("date".equals(parser.getName())) {
String date = parser.nextText();
sms.setDate(date);
} else if ("type".equals(parser.getName())) {
String smsType = parser.nextText();
sms.setType(smsType);
} else if ("body".equals(parser.getName())) {
String body = parser.nextText();
sms.setBody(body);
}
break;
case XmlPullParser.END_TAG:// 结束标签的事件类型
if ("sms".equals(parser.getName())) {
// 把短信还原到数据库
// address,date,type,body;
ContentValues values = new ContentValues();
values.put("address", sms.getAddress());
values.put("date", sms.getDate());
values.put("type", sms.getType());
values.put("body", sms.getBody());
resolver.insert(uri, values);
sms = null;
}
break;
}
// 解析到下一个标签
parser.next();
type = parser.getEventType();
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void deleteSms(){
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
resolver.delete(uri, null, null);
}
}
10_联系人数据库的表结构
联系人相关的表:
1、raw_contacts:存储了联系人的contact_id;
2、data:存储了联系人信息字段的值;
3、mimetypes:存储了联系人信息字段的类型;
读取联系的信息的逻辑:
1、查询raw_contacts:得到contact_id;
2、根据contact_id查询data表;
content://com.android.contacts/raw_contacts
content://com.android.contacts/data
代码:
package com.itheima.readcontacts;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void readContacts(View view){
System.out.println("=======");
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Cursor cursor = resolver.query(uri, new String[]{"contact_id"}, null, null, null);
while(cursor.moveToNext()){
long contact_id = cursor.getLong(0);
System.out.println("contact_id===="+contact_id);
Uri dataUri = Uri.parse("content://com.android.contacts/data");
Cursor dataCursor = resolver.query(dataUri, new String[]{"mimetype","raw_contact_id","data1"}, "raw_contact_id=?",
new String[]{contact_id+""}, null);
while(dataCursor.moveToNext()){
String mimetype = dataCursor.getString(0);
long raw_contact_id = dataCursor.getLong(1);
String data1 = dataCursor.getString(2);
System.out.println("mimetype===="+mimetype);
System.out.println("data1===="+data1);
}
dataCursor.close();
System.out.println("=========================================");
}
cursor.close();
}
}
11_联系人的还原(重点)
联系人相关的表:
1、raw_contacts:存储了联系人的contact_id :记录数加1;
2、data:存储了联系人信息字段的值;
3、mimetypes:存储了联系人信息字段的类型;
content://com.android.contacts/raw_contacts
content://com.android.contacts/data
代码:
package com.itheima.readcontacts;
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.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void restoreContacts(View view) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Cursor cursor = resolver.query(uri, null, null, null, null);
int rownum = cursor.getCount();
cursor.close();
int contact_id = rownum + 1;
// 在raw_contacts表中加入一点条数据
ContentValues values = new ContentValues();
values.put("contact_id", contact_id);
resolver.insert(uri, values);
Uri dataUri = Uri.parse("content://com.android.contacts/data");
// 姓名
ContentValues nameValues = new ContentValues();
nameValues.put("mimetype", "vnd.android.cursor.item/name");
nameValues.put("raw_contact_id", contact_id);
nameValues.put("data1", "wangwu");
resolver.insert(dataUri, nameValues);
// 手机号码
ContentValues phoneValues = new ContentValues();
phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
phoneValues.put("raw_contact_id", contact_id);
phoneValues.put("data1", "18910903535");
resolver.insert(dataUri, phoneValues);
// email
ContentValues emailValues = new ContentValues();
emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
emailValues.put("raw_contact_id", contact_id);
emailValues.put("data1", "wangwu@itcat.cn");
resolver.insert(dataUri, emailValues);
}
}
12_内容观察者
内容观察者(ContentObserver):可以监听到内容提供者中数据变化的情况;
13_短信窃听器(重点)
代码:
package com.itheima.smslistener;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
//注册一个内容观察者
resolver.registerContentObserver(uri, true, new MyObserver(new Handler()));
}
private class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
/**
* 内容提供者中数据发生变化时调用这个方法
*/
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
//查询短信应用
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://sms/");
Cursor cursor = resolver.query(uri, new String[]{"address", "date" , "type", "body"}, null, null, "date desc");
cursor.moveToNext();
String address = cursor.getString(0);
long date = cursor.getLong(1);
long type = cursor.getLong(2);
String body = cursor.getString(3);
System.out.println("address==="+address);
System.out.println("date==="+date);
System.out.println("type==="+type);
System.out.println("body==="+body);
}
}
}