(一)ContentProvider内容提供者,四大组件之一。
ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvier以某种Uri的形式对外提供数据,允许其它应用访问或修改数据,其它应用程序使用ContentResolver根据Uri去访问操作 指定数据。即ContentProvider把私有数据暴露给其他应用,通常,是把私有数据库的数据暴露给其它应用的。ContentProvider只是提供数据的访问接口,是个抽象类。
开发ContentProvider的步骤:
(1)定义自己的ContentProvider类,该类需要继承ContentProvider基类。
(2)在AndroidMainfest.xml文件中注册这个ContentProvier,注册时需要为它绑定一个Uri。
自定义的ContentProvider还需要提供如下几个方法:
public boolean onCreate():该方法在ContentProvider创建后被调用,当其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,并立即回调该onCeate()方法。
public Uri insert(Uri uri,ContentValues values); 根据Ur插入values对应的数据。
public int delete(Uri uri, String selection,String[] selectionArgs):根据Uri删除selection条件所匹配的全部记录。
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs): 根据Uri修改selection条件所匹配的全部记录。
public Cursor query(UrI uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) 根据Uri查询出selection条件所匹配的全部记录,其中projection就是一个列名列表,表明只选择出指定的数据列。
public String getType(Uri uri) 该方法用于返回当前Uri所代表的数据的MIME类型。如果Uri对应的数据可能包括多条记录,那么MIME类型字符串应该以vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么MimE类型字符串应该以vnd.android.cursor.item/开头.
(二)Uri简介
ContentProvider 要求的Uri格式为:content://org.crazyit.providers.dictprovider/words
解释: content:// :这个部分是Android的ContentProvider规定的,就像上网的协议默认是http:// 一样。暴露ContentProvider、访问ContentProvider的协议默认是content:// 。
org.crazyit.providers.dictprovider: 这个部分是ContentProvider的authorities(就相当于网站的域名)。系统就是由这个部分来找到操作哪个ContentProvider的。只要访问指定的ContentProvider,这个部分就是固定的。
words:资源部分(或者说数据部分)。当访问者需要访问不同资源时,这个部分是动态改变的。
为了将一个字符串转换成Uri,Uri工具类提供了parse()静态方法。例如:
Uri uri =Uri.parse("content://org.crazyit.providers.dictprovider/words")
(三)使用ContentResolver操作数据
通过getContentResolver():获取该应用默认的ContentResolver。
ContentResolver可调用如下方法来操作数据:
insert(Uri url,ContentValues values):向Uri对应的ContentProvider中插入values对应的数据。
delete(Uri url,Sring where,String[] selectionArgs): 删除Uri对应的ContentProvider中where提交匹配的数据。
update(Uri uri,ContentValues values,String where,String[] selectionArgs):更新Uri对应的ContentProvider中where提交匹配的数据。
query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) :查询Uri对应的ContentProvider中where提交匹配的数据。
(四)ContentProvider与ContentResolver的关系
不论是ContentProvider还是ContentResolver,它们提供的CRUD方法的第一个参数都是Uri,即Uri是ContentProvider和ContentResolver进行数据交换的标识。ContentResolver对指定Uri执行CRUD等数据操作,但Uri并不是真正的数据中心,这些CRUD操作会委托给该Uri对应的ContentProvider来实现。
例如:假如A应用通过ContentResolver执行CRUD操作,这些CRUD操作都需要指定Uri参数,Android系统就根据该Uri找到对应的ContentProvider(该ContentProvider属于B应用),ContentProvider则负责实现CRUD方法,完成对底层数据的增删改查,这样就可以让A应用访问,修改B应用的数据了。
ContentProvider,Uri,ContentResolver之间的关系,如下:
从图中可以看出,以指定Uri为标识,ContentResolver可以实现“间接调用”ContentProvider的CRUD方法。
(五)配置ContentProvider
Android应用要求所有应用程序组件(Activity,Service,ContentProvider,BroadcastReceiver)都必须显示进行配置
<application>
<provider //注册一个ContentProvider
android:name="com.xrj.dictprovider.DictProvider"
android:authorities="org.crazyit.providers.dictprovider"
android:exported="true"
/>
</application>
配置时有如下属性:
name: 指定该ContentProvider的实现类的类名
authorities:指定该ContentProvider对应的Uri(相当于给这个ContentProvider分配一个域名)
exported:指定该ContentProvider是否允许其他应用调用,如果为false,那么该ContentProvider不允许其他应用调用。
(七)监听ContentProvider的数据改变 : 内容观察者
为了在应用程序中监听ContentProvider数据的改变,需要利用Android提供的ContentObserver基类。监听ContenProvider数据改变的监听器需要继承ContentObserver类,并重写该基类所定义的onChange(boolean selfChange)方法,当它所监听的ContentProvider数据发送改变时,该onChange()方法将会触发。
为了监听ContentProvider数据的改变,需要通过ContentResolver向指定Uri注册ContentObserver几监听器。ContentProvider提供如下方法来注册监听器
registerContentObserver(Uri uri, boolean notifyForDescendents,ContentObserver oberver)
说明:
uri:该监听器所监听的ContentProvider的Uri.
notifyForDescendents: 若为ture,则精确匹配,只要以content://sms开头的uri的数据改变,都能收到通知,比如content://sms/inbox/
若为false,则不是精确匹配。
observer: 监听器实例。
例如:为指定Uri注册监听器
getContentResolver().registerContentObserver(Uri.parse("content://sms"),true,new SmsObserver(new Handler()));
SmsObserver就是ContentObserver的子类。
代码如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 为 content://sms的数据改变注册监听器
getContentResolver().registerContentObserver(Uri.parse("content://sms"),true, new SmsObserver(new Handler()));
}
//提供自定义的ContentObserver监听器类
private final class SmsObserver extends ContentObserver{
public SmsObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange){
//查询发送箱中的短信
Cursor cursor = getContentResolver().query(Uri.parse("content://sms//outbox"),
null,null,null,null);
//遍历查询得到的结果集,即可获取用户正在发送的短信
while(cursor.moveToNext()){
StringBuilder sb = new StringBuilder();
//获取短信的发送地址
sb.append("address=").append(cursor.getString(cursor.getColumnIndex("address")));
//获得短信的标题
sb.append(";subject=").append(cursor.getString(cursor.getColumnIndex("subject")));
//获得短信的内容
sb.append(";body=").append(cursor.getString(cursor.getColumnIndex("body")));
//获取短信的发送时间
sb.append(";time=").append(cursor.getLong(cursor.getColumnIndex("date")));
System.out.println("发送短信:"+sb.toString());
}
}
}
}
注意: 要授予本应用读取短信的权限:
<user-permission android:name="android.permission.REAT_SMS" />