您的位置:首页 > 移动开发 > Android开发

android 学习笔记12-内容提供者

2017-01-16 22:26 483 查看
1、内容提供者

实际的开发中,一般也比较少开发自定义的内容提供者,一般都是使用
应用的数据库是不允许其他应用访问的
内容提供者的作用就是让别的应用访问到你的私有数据,就是一个java类
自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数据库的代码,举例增方法
使用内容提供者可以自己定义访问规则,选择私有数据中哪些共享出去,哪些不共享

注意(特别重要):我们一定要认真配置清单文件xml
<provider android:name="com.example.contentprovider.PersonProvider"//包名.类名
android:authorities="com.example.person"//可以理解为权限
android:exported="true">
</provider>

代码演示:
a,内容提供者的xml文件配置
<provider android:name="com.example.contentprovider.PersonProvider"//包名.类名
android:authorities="com.example.person"//可以理解为权限
android:exported="true">
</provider>
b,内容提供者定义:
public class PersonProvider extends ContentProvider {//继承ContentProvider,重写里面的方法
private SQLiteDatabase db;

//内容提供者创建时调用
@Override
public boolean onCreate() {
MyOpenHelper oh = new MyOpenHelper(getContext());
db = oh.getWritableDatabase();
return false;
}

//values:其他应用要插的数据
@Override
public Uri insert(Uri uri, ContentValues values) {//插入
db.insert("person", null, values);//这里的values是调用者传进来的数据,因为我们内容提供者自己肯定不会去插数据的
return uri;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {//删除
int i = 0;
i = db.delete("person", selection, selectionArgs);
return i;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {//修改
int i = db.update("person", values, selection, selectionArgs);
return i;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {//查询
Cursor cursor = null;
cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder, null);
return cursor;
}

}

c,我们访问者定义
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void insert(View v){
//通过内容提供者把数据插入01数据库
//1.获取contentResolver
ContentResolver resolver = getContentResolver();
//2.访问内容提供者,插入数据
ContentValues values = new ContentValues();
values.put("name", "张三");
values.put("phone", 123456);
values.put("money", 10000);
//arg0:指定内容提供者的主机名
resolver.insert(Uri.parse("content://com.example.people"), values);

values.clear();
values.put("name", "李四");
values.put("phone", 12345);
//arg0:指定内容提供者的主机名
resolver.insert(Uri.parse("content://com.example.people"), values);
}

public void delete(View v){
ContentResolver resolver = getContentResolver();
int i = resolver.delete(Uri.parse("content://com.example.people"), "name = ?", new String[]{"张三"});
System.out.println(i);
}

public void update(View v){
ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("money", 10001);
int i = resolver.update(Uri.parse("content://com.example.people"), values, "name = ?", new String[]{"张三"});
System.out.println(i);//更新的记录数
}

public void query(View v){
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(Uri.parse("content://com.example.people"), null, null, null, null);
while(cursor.moveToNext()){
String name = cursor.getString(1);
String phone = cursor.getString(2);
String money = cursor.getString(3);
System.out.println(name + ";" + phone + ";" + money);
}
}
}

这样大体的定义和访问就可以实现了,但是还有一些问题


2、内容提供者-优化

我们发现上面的内容提供者里面的表名都是写死的 db.insert("person", null, values);
如果我们现在有个handsome表,想操作它就不行了

我们要操作那张表就把表名放到uri里面传过去就行了
resolver.insert(Uri.parse("content://com.example.people/person"), values);
那在提供者就去判断下是哪张表,我们可以使用一个API UriMatcher
在内容提供者里面添加:
//创建uri匹配器
UriMatcher um = new UriMatcher(UriMatcher.NO_MATCH);//UriMatcher.NO_MATCH -1 , 如果都不匹配的话就返回-1
{
//添加匹配规则
//arg0:主机名
//arg1:路径
//arg2:匹配码,这个是自己定义的,如果匹配成功了,就返回这个匹配码
um.addURI("com.example.people", "person", 1);//content://com.example.people/person
um.addURI("com.example.people", "handsome", 2);//content://com.example.people/handsome
um.addURI("com.example.people", "person/#", 3);//content://com.example.people/person/10
}

uri里面还可以携带数字,一般用于查询的条件
取出数字的API:int id = (int) ContentUris.parseId(uri);

mimetype的数据是自己定义的,方便其它同事辨认是那个数据,比如说是person数据

优化后的代码:
public class PersonProvider extends ContentProvider {
private SQLiteDatabase db;
//创建uri匹配器
UriMatcher um = new UriMatcher(UriMatcher.NO_MATCH);
{
//添加匹配规则
//arg0:主机名
//arg1:路径
//arg2:匹配码
um.addURI("com.example.people", "person", 1);//content://com.example.people/person
um.addURI("com.example.people", "handsome", 2);//content://com.example.people/handsome
//*代表所有的字符,#号代表所有的数字
um.addURI("com.example.people", "person/#", 3);//content://com.example.people/person/10
}

//内容提供者创建时调用
@Override
public boolean onCreate() {
MyOpenHelper oh = new MyOpenHelper(getContext());
db = oh.getWritableDatabase();
return false;
}

//values:其他应用要插的数据
//注意这里修改了,里面不再写死表的名称,可以判断到底使用的是哪个表
@Override
public Uri insert(Uri uri, ContentValues values) {
if(um.match(uri) == 1){
db.insert("person", null, values);
//数据库改变了,内容提供者发出通知
//arg0:通知发到哪个uri上,注册在这个uri上的内容观察者都可以收到通知
getContext().getContentResolver().notifyChange(uri, null);
}
else if(um.match(uri) == 2){
db.insert("handsome", null, values);
getContext().getContentResolver().notifyChange(uri, null);
}
else{
throw new IllegalArgumentException("uri传错");
}
return uri;
}

//上面修改了,下面的和上面的类似修改就好了
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int i = 0;
if(um.match(uri) == 1){
i = db.delete("person", selection, selectionArgs);
}
else if(um.match(uri) == 2){
i = db.delete("handsome", selection, selectionArgs);
}
else{
throw new IllegalArgumentException("uri又传错");
}

return i;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int i = db.update("person", values, selection, selectionArgs);
return i;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Cursor cursor = null;
if(um.match(uri) == 1){
cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder, null);
}
else if(um.match(uri) == 2){
cursor = db.query("handsome", projection, selection, selectionArgs, null, null, sortOrder, null);
}
else if(um.match(uri) == 3){
//取出uri末尾携带的数字
long id = ContentUris.parseId(uri);
//查询一条数据,使用主键查询
cursor = db.query("person", projection, "_id = ?", new String[]{"" + id}, null, null, sortOrder, null);
}
return cursor;
}

//返回通过指定uri获取的数据的mimetype,
@Override
public String getType(Uri uri) {
if(um.match(uri) == 1){
return "vnd.android.cursor.dir/person";//也可以定义ab/c,但是为了规范还是规范定义好了
}
else if(um.match(uri) == 2){
return "vnd.android.cursor.dir/handsome";
}
else if(um.match(uri) == 3){
return "vnd.android.cursor.item/person";
}
return null;
}
}

温馨提示:使用内容提供者的好处,为什么不直接把数据库公开呢。我们主要考虑数据的安全性,如果公开了,那么数据可以被任意访问,我们定义了内容提供者
就可以控制访问的规则,需要共享哪个表,或者哪个字段都可以的。


3、应用-读取系统短信

代码演示:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void click1(View v){//点击按钮进行查询
ContentResolver resolver = getContentResolver();//获取一个ContentResolver
//定义我们需要查询的字段,不是所有的字段我们都要
Cursor cursor = resolver.query(Uri.parse("content://sms"), new String[]{"address", "date", "type", "body"}, null, null, null);
while(cursor.moveToNext()){//获取每条短信记录,这里我们用 0,1,2,3 代替,其实也可以用名称查出索引值的
String address = cursor.getString(0);
long date = cursor.getLong(1);
int type = cursor.getInt(2);
String body = cursor.getString(3);
System.out.println(address + ";" + date + ";" + type + ";" + body);
}
}
}

这样不行,因为还需要权限,非常重要的
<uses-permission android:name="android.permission.READ_SMS"/>


4、插入系统短信

代码演示:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void click(View v){
Thread t = new Thread(){
@Override
public void run() {
try {
sleep(10000);//等一会10s界面就会显示来的短信
} catch (InterruptedException e) {
e.printStackTrace();
}
ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("address", 95555);
values.put("date", System.currentTimeMillis());
values.put("type", 1);
values.put("body", "您尾号为XXXX的招行储蓄卡收到转账1,000,000");
resolver.insert(Uri.parse("content://sms"), values);
}
};
t.start();
}
}


5、获取联系人

代码演示:
MainActivity.java
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 resolver = getContentResolver();

Cursor cursor = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[]{"contact_id"},
null, null, null);
while(cursor.moveToNext()){
String contactId = cursor.getString(0);
//使用联系人id作为where条件去查询data表,查询出属于该联系人的信息
Cursor cursorData = resolver.query(Uri.parse("content://com.android.contacts/data"), new String[]{"data1", "mimetype"}, "raw_contact_id = ?",
new String[]{contactId}, null);

Contact contact = new Contact();
while(cursorData.moveToNext()){
String data1 = cursorData.getString(0);
String mimetype = cursorData.getString(1);

if("vnd.android.cursor.item/email_v2".equals(mimetype)){
contact.setEmail(data1);
}
else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
contact.setPhone(data1);
}
else if("vnd.android.cursor.item/name".equals(mimetype)){
contact.setName(data1);
}
}
System.out.println(contact.toString());
}
}
}

Contact.java
public class Contact {

private String name;
private String phone;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Contact [name=" + name + ", phone=" + phone + ", email="
+ email + "]";
}
}


6、插入联系人

先查询raw\_contacts表,确定新的联系人的id应该是多少
把确定的联系人id插入raw\_contacts表
cv.put("contact_id", _id);
cr.insert(Uri.parse("content://com.android.contacts/raw_contacts"), cv);

在data表插入数据
插3个字段:data1、mimetype、raw\_contact_id

cv = new ContentValues();
cv.put("data1", "张三");
cv.put("mimetype", "vnd.android.cursor.item/name");
cv.put("raw_contact_id", _id);
cr.insert(Uri.parse("content://com.android.contacts/data"), cv);

cv = new ContentValues();
cv.put("data1", "123456");
cv.put("mimetype", "vnd.android.cursor.item/phone_v2");
cv.put("raw_contact_id", _id);
cr.insert(Uri.parse("content://com.android.contacts/data"), cv);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: