后台服务与广播消息android_第1页
后台服务与广播消息android_第2页
后台服务与广播消息android_第3页
后台服务与广播消息android_第4页
后台服务与广播消息android_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、,苏州大学计算机科学与技术学院,第4章 后台服务与广播消息,苏州大学计算机科学与技术学院,4.1 Service应用,4.2 接收广播消息,4.3 相关阅读材料:Android开源库EventBus,4.4 本章小结,本章导读,Service和BroadcastReceiver均属Android 系统四大组件。 Service只能后台运行,并且可以和其他组件进行交互。 而广播是一种广泛运用的在应用程序之间传输信息的机制,BroadcastReceiver是对发送出来的广播进行过滤接收并响应的一类组件。,4.1 Service应用,4.1.1 简介 Service可以在很多场合的应用中使用,比如

2、播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。 Service的启动有两种方式:context.startService() 和context.bindService()。,4.1.2 进程内服务,1Service启动流程 context.startService() 启动流程: context.startService()onCreate()onStart()Service runningcontext.stopService()onDestroy()Service s

3、top context.bindService()启动流程: context.bindService()onCreate()onBind()Service running onUnbind()onDestroy()Service stop,2Service生命周期,Service的生命周期并不像Activity那么复杂,它只继承了onCreate()、onStart()、onDestroy()三个方法。 当我们第一次启动Service时,先后调用了onCreate()、onStart()这两个方法;当停止Service时,则执行onDestroy()方法。 这里需要注意的是,如果Service

4、已经启动了,当我们再次启动Service时,不会再执行onCreate()方法,而是直接执行onStart()方法。 它可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己,只要调用一次stopService()方法便可以停止服务,无论调用了多少次的启动服务方法。,3startService示例 4bindService示例 详细内容参见教学视频,4.1.3 跨进程服务,1AIDL机制 由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通

5、常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。Android提供了AIDL工具来处理这项工作。,AIDL(Android Interface Definition Language)是一种IDL语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication,IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。,在Android中,每个应用程序都有自己的进程, Java中是不支持

6、跨进程内存共享的。因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到跨界对象访问的目的。在Java EE中,采用RMI通过序列化传递对象。在Android中,则采用AIDL(Android Interface Definition Language:接口描述语言)方式实现。,AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信。 进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。由于进程之间的通信信息需要双向转换,所以Android采用代理类在背后实现

7、了信息的双向转换,代理类由Android编译器生成,对开发人员来说是透明的。,2选择AIDL的使用场合 官方文档特别提醒我们何时使用AIDL是必要的:只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的Service,以及想在你的Service处理多线程。,4.2 接收广播消息,4.2.1 简介 1广播发送者和广播接收者 Android广播分为两个方面:广播发送者和广播接收者。通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器),用于异步接收广播Intent。广播Intent是通过调用Context.sendBroadcast()发送、BroadcastRec

8、eiver()接收。广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()、Context.sendStickyBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。,BroadcastReceiver 接收广播方式一般有两种: (1)Normal Broadcasts(正常广播),用 Context.sendBroadcast()发送是完全异步的,它们都运行在一个未定义的顺序,通常是在同一时间。 (2)Ordered Broadcasts(有序广播),用

9、Context.sendOrderedBroadcast()发送每次被发送到一个receiver。,2使用场景 (1)同一App内部的同一组件内的消息通信(单个或多个线程之间); (2)同一App内部的不同组件之间的消息通信(单个进程); (3)同一App具有多个进程的不同组件之间的消息通信; (4)不同App之间的组件之间消息通信; (5)Android系统在特定情况下与App之间的消息通信。,3实现原理 (1)广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册; (2)广播发送者通过Binder机制向AMS发

10、送广播; (3)AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中; (4)消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。,4实际应用中的适用性 (1):同一App内部的同一组件内的消息通信(单个或多个线程之间),实际应用中肯定是不会用到广播机制的(虽然可以用),无论是使用扩展变量作用域、基于接口的回调还是Handler-post/Handler-Message等方式,都可以直接处理此类问

11、题。 (2):同一App内部的不同组件之间的消息通信(单个进程),对于此类需求,在有些较复杂的情况下单纯的依靠基于接口的回调等方式不好处理,此时可以直接使用EventBus等。 (3)(4)(5):由于涉及不同进程间的消息通信,此时根据实际业务使用广播机制会显得非常适宜。,4.2.2 发送广播,1自定义BroadcastReceiver 自定义广播接收器需要继承基类BroadcastReceivre,并实现抽象方法onReceive(context, intent)方法。广播接收器接收到相应广播后,会自动回到onReceive()方法。默认情况下,广播接收器也是运行在UI线程,因此,onRec

12、eive方法中不能执行太耗时的操作,否则将因此ANR(Application Not Responding,应用没有响应)。 一般情况下,根据实际业务需求,onReceive方法中都会涉及到与其他组件之间的交互,如发送Notification、启动service等。,下面代码片段是一个简单的广播接收器的自定义: public class MyBroadcastReceiver extends BroadcastReceiver public static final String TAG = MyBroadcastReceiver; Override public void onReceive

13、(Context context, Intent intent) Log.d(TAG, intent: + intent); String name = intent.getStringExtra(name); ,一个BroadcastReceiver对象只有在被调用onReceive(Context, Intent)才有效,当从该函数返回后,该对象就无效了,而结束生命周期。 因此从这个特征可以看出,在所调用的onReceive(Context,Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,应该在startService中来完成。因为当得到其他异步操作所返回的

14、结果时,BroadcastReceiver可能已经无效了。,2BroadcastReceiver注册类型,1)静态注册 直接在AndroidManifest.xml文件中进行注册: . . . ,其中,需要注意的属性有以下: (1)android:exported 此broadcastReceiver能否接收其他App的发出的广播,其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。 (2)android:name 此BroadcastReceiver类名。 (3)android:permission 如果设

15、置,具有相应权限的广播发送方发送的广播才能被此BroadcastReceiver所接收。 (4)android:process BroadcastReceiver运行所处的进程。默认为App的进程。可以指定独立的进程。(Android四大基本组件都可以通过此属性指定自己的独立进程)。,常见的注册形式有: ,2)动态注册 动态注册时,无须在AndroidManifest中注册组件。直接在代码中通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver。 registerReceiver的定义形式如下: registerReceiver(B

16、roadcastReceiver receiver, IntentFilter filter) registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler),3BroadcastReceiver示例 详细内容参见教学视频,4.2.3 有序广播,有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其主要发送方式变为:sen

17、dOrderedBroadcast(intent, receiverPermission, .)。,对于有序广播,其主要特点是: (1)多个具当前已经注册且有效的BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。 (2)先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,

18、使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。,4.2.4 接收系统广播消息,Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相 应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出。,4.3 相关阅读材料:Android开源库EventBus,1使用背景 在编程过程中,当我们想通知其他组件某些事情发生时,我们

19、通常使用观察者模式,在jdk1.5中已经帮助我们实现了观察者模式,我们只需要简单地继承一些类就可以快速使用观察者模式。 当此类需求相对简单时,通过接口以实现回调等方式可以完成,但是当不同组件/控件之间的非常关系纷繁复杂时,基于接口的方案不仅使得代码非常繁琐,同时使得程序逻辑混乱。 基于此,Android开源库EventBus,为此类需求的实现提供了非常方便的方案,可以很方便的帮助我们实现观察者模式。,2什么是EventBus EventBus,也即事件总线。 EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fra

20、gment,Activity,Service,线程之间传递消息,优点是开销小,代码更优雅,以及将发送者和接收者解耦。,3实现步骤 (1)下载EventBus库; (EvnetBus的下载地址: (2)将EventBus.jar放入自己工程的libs目录; (3)定义一个事件,这个事件一旦被EventBus分发出去就是代表某一件事情发生了,这个事件就是某个观察者关心的事情(不需要继承任何类)。 (4)定义观察者,然后将该观察者注册到EventBus; (5)由EventBus分发事件,告知观察者某一件事情发生了; (6)使用完成后从EventBus中反注册观察者。,4回调方法(订阅函数) 在观察

21、者模式中,所有的观察者都需要实现一个接口,这个接口有一个统一的方法: public void onUpdate(); 在EventBus中的观察者通常有四种订阅函数(就是某件事情发生被调用的方法):onEvent,onEventMainThread,onEventBackground,onEventAsync。,5MyEventBusDemo示例 详细内容参见教学视频,4.4本章小结,(1)Service用来在后台处理一些比较复杂的操作,最典型的例子就是音乐播放器的后台播放。虽然Activity中也能完成这样的功能,不过当系统内存紧张时会先把Activity“杀掉”,而很少有Service会“

22、死掉”。另外,一般Activity会在onDestroy时release一些内容,所以,当界面被覆盖时,Activity就不安全了。 (2)Service不是一个单独的进程,除非单独声明,否则它不会运行在单独的进程中,而是和启动它的程序运行在同一个进程中。Service也不是线程,这意味着它将在主线程里运行。,(3)Service与Thread的区别在于:Thread是程序执行的最小单元,可以用Thread来执行一些异步的操作。而Service是Android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的main线程上的。如果是Remote

23、 Service,那么对应的Service则是运行在独立进程的main线程上。 (4)Thread 的运行是独立的,也就是说当一个Activity被finish之后,如果没有主动停止Thread或者Thread里的run方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当Activity被finish之后,不再持有该Thread的引用,也就是不能再控制该Thread。另一方面,没有办法在不同的Activity中对同一Thread 进行控制。,(5)因此可以把Service想象成一种消息服务,可以在任何有Context的地方调用 Context.startService、

24、Context.stopService、Context.bindService、Context.unbindService来控制它,也可以在Service 里注册BroadcastReceiver,通过发送Broadcast来达到控制的目的,这些都是Thread做不到的。 (6)启动Service有两种方法:Context.startService()和Context.bindService()。对于Context.startService(),调用者(Client)与服务端之间没有关联,即使调用者退出,服务仍可运行。对于Context.bindService(),调用者与服务端绑定在一起,可

25、以多个调用者绑定一个服务端,当所有的调用者退出,服务端也就终止。,(7)如果有耗时操作在Service里,就必须开启一个单独的线程来处理。 (8)IntentService是继承自Service的。IntentService相对于Service来说,其优点在于,使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent;对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供了一个思路,如果有耗

26、时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作。,(9)广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。 (10)BroadcastReceiver自身并不实现图形用户界面,但是当它收到某个通知后, BroadcastReceiver可以启动Activity作为响应,或者通过NotificationMananger提醒用户,或者启动Service等等。 (11)在Android里面有各种各样的广播,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播,应用程序开发者也可以监听这些广播并做出程序逻辑的处理。,(12)BroadcastReceiver生命周期只有十秒左右,如果在onReceive()内做超过十秒内的事情,就会报错。每次广播到来时,会重新创建BroadcastReceiver对象,并且调用 onReceive()

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论