ContentProvider用于应用B数据库暴露接口, A应用通过ContentResolver访问B接口,读取数据库数据
Uri格式:
content: // com.example.transupportprovider/trains/122
前缀 : // 唯一标识 / 表 / 表id
ContentProvider的前缀就是:content
唯一标识 : 用包名一般
A应用暴露接口
2.1 DBHelper.java 提供内部数据库访问
package com.example.myapplication;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* 数据库操作的帮助类
* @author denganzhi
*
*/
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context,int version) {
super(context, "atguigu.db", null, version);
}
/**
* 什么时候才会创建数据库文件?
* 1). 数据库文件不存在
* 2). 连接数据库
*
* 什么时候调用?
* 当数据库文件创建时调用(1次)
* 在此方法中做什么?
* 建表
* 插入一些初始化数据
*/
@Override
public void onCreate(SQLiteDatabase db) {
Log.e("TAG", "DBHelper onCreate()");
//建表
String sql = "create table person(_id integer primary key autoincrement, name varchar,age int)";
db.execSQL(sql);
//插入一些初始化数据
db.execSQL("insert into person (name, age) values ('Tom1', 11)");
db.execSQL("insert into person (name, age) values ('Tom2', 12)");
db.execSQL("insert into person (name, age) values ('Tom3', 13)");
}
//当传入的版本号大于数据库的版本号时调用
// 用户版本升级
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e("TAG", "DBHelper onUpgrade()-->"+"oldVersion:"+oldVersion + "newVersion:"+newVersion);
}
// 还有版本下降的时候调用的方法onDowngrade
}
2.2 PersonProvider.java: 实现ContentProvider 接口暴露方法
package com.example.myapplication;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
/**
* 操作person表的provider类
*
*/
public class PersonProvider extends ContentProvider {
//用来存放所有合法的Uri的容器,这里的参数是如果url不能匹配返回的值:-1一般返回
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//保存一些合法的uri
// 前缀:// provider的唯一标识/表明/id
// content://com.atguigu.l09_provider.personprovider/person 不根据id操作
// content://com.atguigu.l09_provider.personprovider/person/3 根据id操作
static {
matcher.addURI("com.example.myapplication.PersonProvider", "/person", 1);
matcher.addURI("com.example.myapplication.PersonProvider", "/person/#", 2); //#匹配任意数字
}
private DBHelper dbHelper;
public PersonProvider() {
Log.e("TAG", "PersonProvider()");
}
// 当内容提供者被创建的时候调用,适合做数据初始化操作
@Override
public boolean onCreate() {
Log.e("TAG", "PersonProvider onCreate()");
dbHelper = new DBHelper(getContext(),1);
return false;
}
/**
* content://com.atguigu.l09_provider.personprovider/person 不根据id查询
* content://com.atguigu.l09_provider.personprovider/person/3 根据id查询
* 查询表数据:
* URI:地址
* projection: 查询那些字段
* String selection,
String[] selectionArgs 查询条件,条件中可能有?
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Log.e("TAG", "PersonProvider query()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//1.匹配uri, 返回code
int code = matcher.match(uri);
//如果合法, 进行查询
if(code==1) {//不根据id查询,配合1
Cursor cursor = database.query("person", projection, selection, selectionArgs, null, null, null);
return cursor;
} else if(code==2) {//根据id查询,匹配2
//得到id
long id = ContentUris.parseId(uri);
//查询
Cursor cursor = database.query("person", projection, "_id=?", new String[]{id+""}, null, null, null);
return cursor;
} else {//如果不合法, 抛出异常
throw new RuntimeException("查询的uri不合法");
}
}
/**
* content://com.atguigu.l09_provider.personprovider/person 插入
* content://com.atguigu.l09_provider.personprovider/person/3 根据id插入(没有)
* values: map接口插入数据
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.e("TAG", "PersonProvider insert()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配uri, 返回code
int code = matcher.match(uri);
//如果合法, 进行插入
if(code==1) {
long id = database.insert("person", null, values);
//将id添加到uri中
uri = ContentUris.withAppendedId(uri, id);
database.close();
return uri;
} else {
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("插入的uri不合法");
}
}
/**
* content://com.atguigu.l09_provider.personprovider/person 不根据id删除
* content://com.atguigu.l09_provider.personprovider/person/3 根据id删除
*
* String selection, String[] selectionArgs: 删除条件
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.e("TAG", "PersonProvider delete()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配uri, 返回code
int code = matcher.match(uri);
int deleteCount = -1;
//如果合法, 进行删除
if(code==1) {
deleteCount = database.delete("person", selection, selectionArgs);
} else if(code==2) {
long id = ContentUris.parseId(uri);
deleteCount = database.delete("person", "_id="+id, null);
} else {
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("删除的uri不合法");
}
database.close();
return deleteCount;
}
/**
* content://com.atguigu.l09_provider.personprovider/person 不根据id更新
* content://com.atguigu.l09_provider.personprovider/person/3 根据id更新
*
* values: map更新数据
* String selection,
String[] selectionArgs 更新条件
*/
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Log.e("TAG", "PersonProvider update()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配uri, 返回code
int code = matcher.match(uri);
int updateCount = -1;
//如果合法, 进行更新
if(code==1) {
updateCount = database.update("person", values, selection, selectionArgs);
} else if(code==2) {
long id = ContentUris.parseId(uri);
updateCount = database.update("person", values, "_id="+id, null);
} else {
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("更新的uri不合法");
}
database.close();
return updateCount;
}
// MIME:
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
B应用使用 ContentResolver 访问暴露接口,协议 Uri 的格式
通过ContentResolver 接口,访问ContentProvider 暴露的方法
public static String prividerStr="content://com.example.myapplication.PersonProvider/person";
/*
* 通过ContentResolver调用ContentProvider查询所有记录
*/
public void selectProvier(View v) {
//1. 得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2. 调用其query, 得到cursor
Uri uri = Uri.parse("content://com.example.myapplication.personprovider/person/1");
uri = Uri.parse(prividerStr);
Cursor cusor = resolver.query(uri, null, null, null, null);
//3. 取出cursor中的数据, 并显示
if(cusor!=null){
while(cusor.moveToNext()) {
int id = cusor.getInt(0);
String name = cusor.getString(1);
Toast.makeText(this, id+" : "+name, 1).show();
}
cusor.close();
}
}
public void addFun(View view) {
//1. 得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2. 调用其insert
Uri uri = Uri.parse(prividerStr);
//uri = Uri.parse("content://com.atguigu.l09_provider.personprovider/person/3");
ContentValues values = new ContentValues();
values.put("name", "JACK");
uri = resolver.insert(uri, values);
Toast.makeText(this, uri.toString(), 1).show();
}
public void updateFun(View view) {
//1. 得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2. 执行update
Uri uri = Uri.parse("content://com.example.myapplication.PersonProvider/person/10");
ContentValues values = new ContentValues();
values.put("name", "JACK2");
// 返回更新成功个数
int updateCount = resolver.update(uri, values, null, null);
Toast.makeText(this, "updateCount="+updateCount, 1).show();
}
public void deleteFun(View view) {
//1. 得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2. 执行delete
Uri uri = Uri.parse("content://com.example.myapplication.PersonProvider/person/2");
int deleteCount = resolver.delete(uri, null, null);
Toast.makeText(this, "deleteCount="+deleteCount, 1).show();
}
案例1: 读取联系人
AndroidManifest.xml
Java 代码:系统已经提供了现成的CONTENT_URI ,把数据库字段封装成了常量
private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE =10 ;
public void selectContacts(View view) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
} else
{
selectContacts();
}
}
public void selectContacts() {
ContentResolver resolver = getContentResolver();
//执行查询得到cursor
String[] projection = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
//取出其中的数据保存到data
while(cursor.moveToNext()) {
String name = cursor.getString(0);
String number = cursor.getString(1);
Map map = new HashMap();
map.put("name", name);
map.put("number", number);
Log.e("denganzhi","name:"+name + "number:"+ number);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE)
{
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
selectContacts();
} else
{
// Permission Denied
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
案例2: 读取sd卡本地视频路径
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_local);
/**
* 读取sd卡中本地的所有的视频
* Android系统本地的视频播放器,已经把SD卡上的视频扫描,
* 把数据存储数据库中了,
* 所以只是需要使用内容提供者读取系统播放器的数据即可
*/
ContentResolver contentProvider= getContentResolver();
// 系统封装 Uri
Uri uri= MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] objs={
MediaStore.Video.Media.DISPLAY_NAME, // 视频文件在sdcard上名称
MediaStore.Video.Media.DURATION, // 视频总时长
MediaStore.Video.Media.SIZE, // 视频大小
MediaStore.Video.Media.DATA, // 视频绝对地址
MediaStore.Video.Media.ARTIST, // 歌曲演唱者
};
Cursor cursor= contentProvider.query(uri,objs,null,null,null);
if(cursor!=null){
while(cursor.moveToNext()){
String name = cursor.getString(0);
long duration = cursor.getLong(1);
long size = cursor.getLong(2);
String path = cursor.getString(3);
String artist = cursor.getString(4);
Log.e("denganzhi","name:"+name+ " duration:"+duration +" size:"+size +" path:"+path +" artist:"+artist);
}
}
cursor.close();
}
案例3:获取本地所有的音频文件:
ContentResolver contentProvider= getContentResolver();
// 系统封装 Uri
Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] objs={
MediaStore.Audio.Media.DISPLAY_NAME, // 音频文件在sdcard上名称
MediaStore.Audio.Media.DURATION, // 音频总时长
MediaStore.Audio.Media.SIZE, // 音频大小
MediaStore.Audio.Media.DATA, // 音频绝对地址
MediaStore.Audio.Media.ARTIST, // 歌曲演唱者
};
Cursor cursor= contentProvider.query(uri,objs,null,null,null);
if(cursor!=null){
while(cursor.moveToNext()){
String name = cursor.getString(0);
long duration = cursor.getLong(1);
long size = cursor.getLong(2);
String path = cursor.getString(3);
String artist = cursor.getString(4);
Log.e("denganzhi","name:"+name+ " duration:"+duration +" size:"+size +" path:"+path +" artist:"+artist);
}
}
cursor.close();
源码路径:https://download.csdn.net/download/dreams_deng/12233364
原理:C应用注册B应用的内容观察者,B应用在数据库操作crud的时候
发布url[ getContentResolver().notifyChange(uri,null)],
那么C应用就可以监听到 resolver.registerContentObserver(uri, true, new ContentObserver(new Handler()) {
案例: 监听收短信,可以实现读取验证码,获取用户短信上传服务器
1. 使用广播实现,短信窃听器
AndroidManifest.xml
权限申请
// 判断权限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECEIVE_SMS)
!= PackageManager.PERMISSION_GRANTED)
{
// 权限申请
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECEIVE_SMS},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
} else
{
//具备权限发短信、接收短信权限
}
SmsReceiver 接收短信广播
package ndkdemo.denganzhi.com.xmlversion;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SmsReceiver extends BroadcastReceiver {
String Tag="denganzhi1";
@Override
public void onReceive(Context context, Intent intent) {
Log.e("denganzhi", "短信到来了....... ");
// 短信的格式是pub 格式 https://blog.csdn.net/zx249388847/article/details/52597990/
// 谷歌考虑 Android 工程师比较难理解,直接
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
if (pdus != null && pdus.length > 0) {
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
byte[] pdu = (byte[]) pdus[i];
// 把pud 转化为短信 对象
messages[i] = SmsMessage.createFromPdu(pdu);
}
for (SmsMessage message : messages) {
String content = message.getMessageBody();// 得到短信内容
String sender = message.getOriginatingAddress();// 得到发信息的号码
// if (sender.equals("110")) {
// abortBroadcast();// 中止发送
// Log.e("TAG", "此号码为黑名单号码,已拦截!");
// }
Date date = new Date(message.getTimestampMillis());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String sendContent = format.format(date) + ":" + sender + "--"
+ content;
// SmsManager smsManager = SmsManager.getDefault();// 发信息时需要的
// smsManager.sendTextMessage("", null, sendContent, null,
// null);// 转发给
// 打印短信内容
Log.e(Tag, sendContent);
}
}
}
}
2. 内容观察者使用,监听短信变化,读取变化短信收到的,搜集用户信息
读写读取:
public void readSmsContext(View view){
Uri uri = Uri.parse("content://sms/");
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { "address", "date",
"type", "body" }, null, null, null);
while (cursor.moveToNext()) {
String address = cursor.getString(0);
String date = cursor.getString(1);
String type = cursor.getString(2);
String body = cursor.getString(3);
Log.e(Tag,"address:" + address);
Log.e(Tag,"date:" + date);
Log.e(Tag,"type:" + type);
Log.e(Tag,"body:" + body);
Log.e(Tag,"--------------------");
}
cursor.close();
}
MainActivity 功能实现:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_SMS)
!= PackageManager.PERMISSION_GRANTED)
{
// 权限申请
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_SMS},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
} else
{
//具备权限发短信、接收短信权限
}
// 短信Uri, 注册短信 Uri
Uri uri= Uri.parse("content://sms/");
ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(uri, true, new ContentObserver(new Handler()) {
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// 读取变化的短信
//全部短信
// public static final String SMS_URI_ALL = "content://sms/";
//收件箱短信
// public static final String SMS_URI_INBOX = "content://sms/inbox";
//发件箱短信
// public static final String SMS_URI_SEND = "content://sms/sent";
//草稿箱短信
// public static final String SMS_URI_DRAFT = "content://sms/draft";
Uri uri = Uri.parse("content://sms/inbox");
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { "address", "date",
"type", "body" }, null, null, null);
while (cursor.moveToNext()) {
String address = cursor.getString(0);
String date = cursor.getString(1);
String type = cursor.getString(2);
String body = cursor.getString(3);
Log.e(Tag,"--------------------");
Log.e(Tag,"address:" + address);
Log.e(Tag,"date:" + date);
Log.e(Tag,"type:" + type);
Log.e(Tag,"body:" + body);
Log.e(Tag,"--------------------");
break;
}
cursor.close();
}
});
}