day09
1 为什么需要内容提供者(contentProvider)
使用内容提供者 把私有的数据库内容给暴露出来
2 内容提供者原理

[1]内容提供者把数据进行封装然后提供出来 其他应用都是通过内容解析者来访问
[2]定义内容提供者 定义一个类继承ContentProvider
3 实现内容提供者步骤
[1]定义一个类继承contentProvider
[2]在清单文件里配置内容提供者
<providerandroid: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);}@Overridepublic boolean onCreate() {myOpenHelper = new MyOpenHelper(getContext());return false;}/*** URL http://www.baidu.com* URI*/@Overridepublic 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("你的路径不匹配");}}@Overridepublic String getType(Uri uri) {return null;}@Overridepublic Uri insert(Uri uri, ContentValues values) {int code = sURIMatcher.match(uri);if(code == INSERTSUCCESS){//操作数据库 说明数据匹配成功SQLiteDatabase db = myOpenHelper.getWritableDatabase();//返回值代表新插入行数的IDlong insert = db.insert("info", null, values);Uri uri2 = Uri.parse("com.phone.insert/"+insert);return uri2;}else{//路径不匹配throw new IllegalArgumentException("你的路径不匹配");}}@Overridepublic 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("你的路径不匹配");}}@Overridepublic 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 {@Overrideprotected 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);}@Overridepublic 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"});}@Overridepublic 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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);}//当内容发送改变的时候调用@Overridepublic void onChange(boolean selfChange) {System.out.println("ahahha数据库的内容发生了改变");super.onChange(selfChange);}}}
9 内容观察者的应用场景
只言片语任我说,提笔句句无需忖。落笔不知寄何人,唯有邀友共斟酌。
浙公网安备 33010602011771号