使用内容提供者 把私有的数据库内容给暴露出来
2 内容提供者原理
[1]内容提供者把数据进行封装然后提供出来 其他应用都是通过内容解析者来访问
[2]定义内容提供者 定义一个类继承ContentProvider
3 实现内容提供者步骤
[1]定义一个类继承contentProvider
[2]在清单文件里配置内容提供者
<provider
android:name="com.phone.dbexec.AccountProvider"
android:authorities="com.phone.provider" >
</provider>
[3]写一个静态代码块
[4]暴露你想暴露的方法(增删改查)
[5]如果你发现日志中出现类似Pub com.phone.provider:com.phone.db.AccountProvider 这样日志,说明你的内容提供没有问题.
[6]其他应用就可以通过内容的解析者去操作数据库
app1:
package com.phone.dbexec;
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 AccountProvider extends ContentProvider {
private static int QUERYSUCCESS = 0;
private static int INSERTSUCCESS = 1;
private static int UPDATESUCCESS = 2;
private static int DELETESUCCESS = 3;
private MyOpenHelper myOpenHelper;
//[1]定义一个urimathcher 定义路径匹配器
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//[2]定义静态代码块 添加匹配规则
static
{
/**
* authority 注意 这个参数和你在清单文件里面定义的要一样
* path content://com.phone.provider/query
*/
sURIMatcher.addURI("com.phone.provider", "query", QUERYSUCCESS);
sURIMatcher.addURI("com.phone.provider", "insert", INSERTSUCCESS);
sURIMatcher.addURI("com.phone.provider", "update", UPDATESUCCESS);
sURIMatcher.addURI("com.phone.provider", "delete", DELETESUCCESS);
}
@Override
public boolean onCreate() {
myOpenHelper = new MyOpenHelper(getContext());
return false;
}
/**
* URL http://www.baidu.com
* URI
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int code = sURIMatcher.match(uri);
if(code == QUERYSUCCESS){
//说明路径匹配成功
//把query方法实现 数据库的查询方法
//对数据库进行查询的操作
//想操作数据库必须获得sqlitedatabase对象
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
//cursor不能关闭注意
return cursor;
}else{
//路径不匹配
throw new IllegalArgumentException("你的路径不匹配");
}
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int code = sURIMatcher.match(uri);
if(code == INSERTSUCCESS){
//操作数据库 说明数据匹配成功
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//返回值代表新插入行数的ID
long insert = db.insert("info", null, values);
Uri uri2 = Uri.parse("com.phone.insert/"+insert);
return uri2;
}else{
//路径不匹配
throw new IllegalArgumentException("你的路径不匹配");
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int match = sURIMatcher.match(uri);
if(match == DELETESUCCESS){
//说明路径匹配成功 对数据库进行删除的操作
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//代表影响的行数
int delete = db.delete("info", selection, selectionArgs);
return delete;
}else{
//路径不匹配
throw new IllegalArgumentException("你的路径不匹配");
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int match = sURIMatcher.match(uri);
if(match == UPDATESUCCESS){
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
int update = db.update("info", values, selection, selectionArgs);
return update;
}else{
//路径不匹配
throw new IllegalArgumentException("你的路径不匹配");
}
}
}
package com.phone.dbexec;
import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyOpenHelper helper = new MyOpenHelper(getApplicationContext());
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.query("info", null, null, null, null, null, null);
if(cursor!=null && cursor.getCount()>0){
while(cursor.moveToNext()){
String name = cursor.getString(1);
String money = cursor.getString(2);
System.out.println("name:"+name+" money:"+money);
}
}
}
}
package com.phone.dbexec;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
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))");
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"张三","5000"});
db.execSQL("insert into info(name,money) values(?,?)",new String[]{"李四","3000"});
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
app2:
package com.phone.readother;
import android.support.v7.app.ActionBarActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 读取66应用的私有的数据库
/**
* path 路径 Account.db factory 游标工厂 flages 访问的模式
*/
// 第一种方式
/*
* SQLiteDatabase db = SQLiteDatabase.openDatabase(
* "data/data/com.phone.dbexec/databases/Acount.db", null,
* SQLiteDatabase.OPEN_READWRITE); Cursor cursor = db.query("info",
* null, null, null, null, null, null); if(cursor!=null &&
* cursor.getCount()>0){ while(cursor.moveToNext()){ String name =
* cursor.getString(1); String money = cursor.getString(2);
*
* System.out.println("67应用--name:"+name+" money:"+money); } }
*/
// 第二种方式
// 由于66应用里面的私有数据库已经通过内容提供者给暴露出来了,所以直接通过内容的解析者进行访问
// [1]拿到内容的解析者 直接通过上下文获取
// 路径和你在66应用定义的路径一样
Uri uri = Uri.parse("content://com.phone.provider/query");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String name = cursor.getString(1);
String money = cursor.getString(2);
System.out.println("67应用--name:" + name + " money:" + money);
}
}
}
// 对数据库进行增加一条记录
// 由于66应用里面的私有数据库已经通过内容提供者给暴露出来了,所以直接通过内容的解析者进行访问
public void click1(View v) {
Uri uri = Uri.parse("content://com.phone.provider/insert");
ContentValues values = new ContentValues();
values.put("name", "赵6");
values.put("money", 10000);
Uri insert = getContentResolver().insert(uri, values);
System.out.println("insert:" + insert);
}
// 对数据库进行删除一条记录
public void click2(View v) {
Uri uri = Uri.parse("content://com.phone.provider/delete");
int delete = getContentResolver().delete(uri, "name=?", new String[]{"赵6"});
Toast.makeText(getApplicationContext(), "删除了"+delete+"行", 1).show();
}
// 对数据库进行更新一条记录
public void click3(View v) {
Uri uri = Uri.parse("content://com.phone.provider/update");
ContentValues values = new ContentValues();
values.put("money", 10);
int update = getContentResolver().update(uri, values, "name=?", new String[]{"赵6"});
Toast.makeText(getApplicationContext(), "更新了"+update+"行", 1).show();
}
// 对数据库进行查找一条记录
public void click4(View v) {
Uri uri = Uri.parse("content://com.phone.provider/query");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String name = cursor.getString(1);
String money = cursor.getString(2);
System.out.println("67应用--name:" + name + " money:" + money);
}
}
}
}
4 备份短信案例
package com.phone.backupsms;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import org.xmlpull.v1.XmlSerializer;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.util.Xml;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 点击按钮 查询短信数据库内容 然后进行备份
public void click(View v) {
try {
// [1]获取xml序列化实例
XmlSerializer serializer = Xml.newSerializer();
// [2]设置序列化参数
File file = new File(Environment.getExternalStorageDirectory()
.getPath(), "sms-BackUp.xml");
FileOutputStream fos = new FileOutputStream(file);
serializer.setOutput(fos, "utf-8");
// [3]开始写xml文档开头
serializer.startDocument("utf-8", true);
// [4]开始写根节点
serializer.startTag(null, "smss");
// [5]由于短信数据库 系统也通过内容提供者给暴露出来了 所以我们只需要通过内容解析者去操作数据库
Uri uri = Uri.parse("content://sms/");
Cursor cursor = getContentResolver().query(uri,
new String[] { "address", "date", "body" }, null, null,
null);
while (cursor.moveToNext()) {
String address = cursor.getString(0);
String date = cursor.getString(1);
String body = cursor.getString(2);
// [6]写sms节点
serializer.startTag(null, "sms");
// [7]写address节点
serializer.startTag(null, "address");
serializer.text(address);
serializer.endTag(null, "address");
// [8]写date节点
serializer.startTag(null, "date");
serializer.text(date);
serializer.endTag(null, "date");
// [9]写body节点
serializer.startTag(null, "body");
serializer.text(body);
serializer.endTag(null, "body");
serializer.endTag(null, "sms");
}
serializer.endTag(null, "smss");
serializer.endDocument();
} catch (Exception e) {
e.printStackTrace();
}
}
}
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
5 利用内容解析者插入短信
package com.phone.insertsms;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击按钮 往短信数据库里面插入一条数据
public void click(View v){
Uri uri = Uri.parse("content://sms/");
ContentValues values = new ContentValues();
values.put("address", "955");
values.put("body", "您的余额为0.0000元");
values.put("date", System.currentTimeMillis());
getContentResolver().insert(uri, values);
}
}
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
6 读取联系人案例
三张重要的表
1 data data1 里面存的是所有联系人的信息
2 data表里面的raw_contact_id实际是raw_contact表的contact_id
3 data表里面的mimetype_id列 实际对应mimetype表
实现步骤
[1]先读取raw_contact表 读取contact_id字段 从而就知道手机里一共有几条联系人
[2]在读取data表 根据raw_contact_id去读取data1列和mimetype列
package com.phone.readcontacts;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
public class ReadContactUtils {
public static List<Contacts> readContacts(Context context) {
// [0]创建集合对象
List<Contacts> contactsLists = new ArrayList<Contacts>();
// [1]由于联系人的数据库也是通过内容提供者暴露出来了 所以我想操作数据库直接使用内容解析者
// [2]先查询raw_contacts表 contact_id列
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = context.getContentResolver().query(uri,
new String[] { "contact_id" }, null, null, null);
while (cursor.moveToNext()) {
String contact_id = cursor.getString(0);
if (contact_id != null) {
// 创建javabean对象
Contacts contacts = new Contacts();
contacts.setId(contact_id);
// [3]根据raw_contact_id 去查询data表 data列和mimetype_id列
// 小细节 查询的不是data表 查询的是view_data的视图
Cursor dataCursor = context.getContentResolver().query(dataUri,
new String[] { "data1", "mimetype" },
"raw_contact_id=?", new String[] { contact_id }, null);
while (dataCursor.moveToNext()) {
String data1 = dataCursor.getString(0);
String mimetype = dataCursor.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)) {
System.out.println("姓名:" + data1);
contacts.setName(data1);
} else if ("vnd.android.cursor.item/phone_v2"
.equals(mimetype)) {
System.out.println("电话号码:" + data1);
contacts.setPhone(data1);
} else if ("vnd.android.cursor.item/email_v2"
.equals(mimetype)) {
System.out.println("邮箱:" + data1);
contacts.setEmail(data1);
}
}
// 把javabean对象加入到集合中
contactsLists.add(contacts);
}
}
return null;
}
}
<uses-permission android:name="android.permission.READ_CONTACTS"/>
7 利用内容内容解析者插入一条联系人
[1]先往raw_contact表 往contact_id列插入数据
[2]同步到data表 data1列存的是所有联系人的数据
//[2]获取数据
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().
toString().trim();String email = et_email.getText().
toString().trim();- //定义uri
- Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
- Uri dataUri = Uri.parse("content://com.android.contacts/data");
- //先查询一下raw_contacts表中一共有几条数据 行数+1就是contact_id的值
- Cursor cursor = getContentResolver().query(uri, null, null, null, null);
- int count = cursor.getCount();
- //代表当前联系人的id
- int contact_id = count + 1;
- //把数据插入到联系人数据库 由于联系人的数据库也是通过内容提供者暴露出来 所以我们直接通过内容解析者去操作数据库
- ContentValues valus = new ContentValues();
- values.put("contact_id", contact_id);
- getContentResolver().insert(uri, values);
- //把name 插入到data表
- ContentValues nameValues = new ContentValues();
- //把数据插入到data1列
- nameValues .put("data1", name);
- //告诉数据库我们插入的数据是属于哪条联系人
- nameValues .put("raw_contact_id", contact_id);
- //告诉数据库插入的数据的数据类型
- nameValues .put("mimetype", "vnd.android.cursor.item/name");
- getContentResolver().insert(dataUri, nameValues );
- //把phone 插入到data表
- ContentValues phoneValues = new ContentValues();
- //把数据插入到data1列
- phoneValues.put("data1", phone);
- //告诉数据库我们插入的数据是属于哪条联系人
- phoneValues.put("raw_contact_id", contact_id);
- //告诉数据库插入的数据的数据类型
- phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
- getContentResolver().insert(dataUri, phoneValues);
- //把email插入到data表
- ContentValues emailValues = new ContentValues();
- //把数据插入到data1列
- emailValues .put("data1", email);
- //告诉数据库我们插入的数据是属于哪条联系人
- emailValues .put("raw_contact_id", contact_id);
- //告诉数据库插入的数据的数据类型
- emailValues .put("mimetype", "vnd.android.cursor.item/email_v2");
- getContentResolver().insert(dataUri, emailValues );
8 内容观察者
内容提供者 需要在清单文件配置
package com.phone.registercontentobsever;
import android.app.Activity;
import android.database.ContentObserver;
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);
//[1]注册内容观察者
Uri uri = Uri.parse("content://com.phone.provider");
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
}
//[2]定义一个内容观察者
private class MyContentObserver extends ContentObserver{
public MyContentObserver(Handler handler) {
super(handler);
}
//当内容发送改变的时候调用
@Override
public void onChange(boolean selfChange) {
System.out.println("ahahha数据库的内容发生了改变");
super.onChange(selfChange);
}
}
}
9 内容观察者的应用场景