1.题记

Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。

广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似。

2.Service开发详解

服务的开发比较简单,如下: 

第一步:继承Service类 

public class SMSService extends Service { } 

第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置: 

<service android:name=".SMSService" /> 

服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,访问者与服务之间没有关连,即使访问者退出了,服务仍然运行。使用bindService()方法启用服务,访问者与服务绑定在了一起,访问者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。 

采用Context.startService()方法启动服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。

startService 与 bindService区别如下:

  1. 生命周期:startService方式启动,Service是通过接受Intent并且会经历onCreate和onStart。当用户在发出意图使之销毁时会经历onDestory而bindService方式启动,与Activity绑定的时候,会经历onCreate和onBind,而当Activity被销毁的时候,Service会先调用onUnbind然后是onDestory.
  2. 控制方式:牵着的控制方式需要使用固定的方法,对Service进行单一的操作。而后者由于与Activity绑定,不用考虑其生命周期问题,并且从发送Intent的被动操作,变为可以主动对Service对象进行操作,我们深圳可以建立一个Handler类,对Service进行相关的操作。大大加强了Service的灵活性、可操作性。
  3. 总结:对于简单的应用startService启动方式能带来更少的代码,简单的操作,对于复杂的应用bindService方式,虽然带来的更多的编码,但同时也带来了更好的可操作性,使其实用起来更像Activity。

3.BroadcastReceiver开发详解

3.1BroadcastReceiver广播接收者

要实现一个广播接收者方法如下: 

第一步:继承BroadcastReceiver,并重写onReceive()方法。 

public class IncomingSMSReceiver extends BroadcastReceiver { 

    @Override public void onReceive(Context context, Intent intent) { 

    } 



第二步:订阅感兴趣的广播Intent,订阅方法有两种: 

第一种:使用代码进行订阅

  1. IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
  2. IncomingSMSReceiver receiver = new IncomingSMSReceiver();
  3. registerReceiver(receiver, filter);

第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅:

  1. <receiver android:name=".IncomingSMSReceiver">
  2. <intent-filter>
  3. <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
  4. </intent-filter>
  5. </receiver>

广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;然而有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。优先级别声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置 。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。另外,有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。 

Context.sendBroadcast() 

   发送的是普通广播,所有订阅者都有机会获得并进行处理。 

Context.sendOrderedBroadcast() 

   发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast()),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。 

系统收到短信,发出的广播属于有序广播。如果想阻止用户收到短信,可以通过设置优先级,让你们自定义的接收者先获取到广播,然后终止广播,这样用户就接收不到短信了。

3.2广播接收者的响应

在Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法, onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。当onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。

  1. public class IncomingSMSReceiver extends BroadcastReceiver {
  2. @Override public void onReceive(Context context, Intent intent) {
  3. //发送Intent启动服务,由服务来完成比较耗时的操作
  4. Intent service = new Intent(context, XxxService.class);
  5. context.startService(service);
  6. }
  7. }

3.3常见系统广播接收者

除了短信到来广播Intent,Android还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent。 
接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的<application>节点里订阅此Intent: 

<receiver android:name=".IncomingSMSReceiver"> 

    <intent-filter> 

         <action android:name="android.intent.action.BATTERY_CHANGED"/> 

    </intent-filter> 

</receiver> 

 接收开机启动广播Intent,在AndroidManifest.xml文件中的<application>节点里订阅此Intent: 

<receiver android:name=".IncomingSMSReceiver"> 

    <intent-filter> 

         <action android:name="android.intent.action.BOOT_COMPLETED"/> 

    </intent-filter> 

</receiver> 

并且要进行权限声明: 

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

接收短信广播Intent,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver"> 

   <intent-filter>

<action android:name="android.provider.Telephony.SMS_RECEIVED"/>

</intent-filter>

</receiver> 

在AndroidManifest.xml文件中添加以下权限: 

<uses-permission android:name="android.permission.RECEIVE_SMS"/><!-- 接收短信权限 --> 

<uses-permission android:name="android.permission.SEND_SMS"/><!-- 发送短信权限 -->

4.简单实例

下面是整合了Service与BroadCastReceiver的一个小例子,主要实现的是,在后台开通一个计数服务,当计数能被5整除时候则广播该数。主要代码如下:

ClientActivity绑定服务:

  1. public class ClientActivity extends Activity {
  2. /** Called when the activity is first created. */
  3. private ICountService countService;
  4. @Override
  5. public void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.main);
  8. this.bindService(new Intent(this, CountService.class),
  9. this.serviceConnection, BIND_AUTO_CREATE);
  10. }
  11. @Override
  12. protected void onDestroy() {
  13. super.onDestroy();
  14. this.unbindService(serviceConnection);
  15. }
  16. @Override
  17. public boolean onKeyUp(int keyCode, KeyEvent event) {
  18. if(keyCode==KeyEvent.KEYCODE_BACK)
  19. {
  20. this.unbindService(serviceConnection);
  21. this.finish();
  22. return true;
  23. }
  24. return super.onKeyUp(keyCode, event);
  25. }
  26. private ServiceConnection serviceConnection = new ServiceConnection() {
  27. @Override
  28. public void onServiceConnected(ComponentName name, IBinder service) {
  29. countService = (ICountService) service;// 对于本地服务,获取的实例和服务onBind()返回的实例是同一个
  30. int i = countService.getCount();
  31. Log.v("CountService", "Count is " + i);
  32. }
  33. @Override
  34. public void onServiceDisconnected(ComponentName name) {
  35. countService = null;
  36. }
  37. };
  38. }

计数服务代码:

  1. package com.sulang.android.service;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.Binder;
  5. import android.os.IBinder;
  6. import android.util.Log;
  7. /*
  8. *@author 七里香的悔恨,2011-3-17
  9. *CountService.java
  10. *Blog:[url]http://bigboy.iteye.com/[/url]
  11. */
  12. public class CountService extends Service {
  13. private boolean quit=false;
  14. private int count;
  15. private ServiceBinder serviceBinder = new ServiceBinder();
  16. private final static String DIVIDE_RESULT="com.sulang.android.service.DIVIDE";
  17. @Override
  18. public IBinder onBind(Intent intent) {
  19. return serviceBinder;
  20. }
  21. public class ServiceBinder extends Binder implements ICountService {
  22. @Override
  23. public int getCount() {
  24. return count;
  25. }
  26. }
  27. @Override
  28. public void onCreate() {
  29. super.onCreate();
  30. new Thread(new Runnable() {
  31. @Override
  32. public void run() {
  33. while (!quit) {
  34. try {
  35. );
  36. } catch (InterruptedException e) {}
  37. count++;
  38. ==0)
  39. {
  40. Intent intent = new Intent(DIVIDE_RESULT);
  41. intent.putExtra("count", count);
  42. sendBroadcast(intent);
  43. }
  44. Log.i("CountService", count+"");
  45. }
  46. }
  47. }).start();
  48. }
  49. @Override
  50. public void onDestroy() {
  51. super.onDestroy();
  52. this.quit = true;
  53. }
  54. }

计数广播接收者:

  1. package com.sulang.android.service;
  2. import android.content.BroadcastReceiver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.widget.Toast;
  6. /*
  7. *@author 七里香的悔恨,2011-3-18
  8. *CountServiceBroadcast.java
  9. *Blog:[url]http://bigboy.iteye.com/[/url]
  10. */
  11. public class CountServiceBroadcast extends BroadcastReceiver {
  12. private final static String DIVIDE_RESULT="com.sulang.android.service.DIVIDE";
  13. @Override
  14. public void onReceive(Context context, Intent intent) {
  15. String action = intent.getAction();
  16. if(action.equals(DIVIDE_RESULT))
  17. {
  18. );
  19. Toast.makeText(context, "当前数字为:"+count, Toast.LENGTH_LONG).show();
  20. }
  21. }
  22. /**
  23. * 使用代码进行订阅广播
  24. * IntentFilter filter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
  25. * IncomingSMSReceiver receiver=new IncomingSMSReceiver();
  26. * registerReceiver(receiver,filter);
  27. */
  28. }

manifest文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.sulang.android.service"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-sdk android:minSdkVersion="4" />
  7. <application android:icon="@drawable/icon" android:label="@string/app_name">
  8. <activity android:name=".ClientActivity"
  9. android:label="@string/app_name">
  10. <intent-filter>
  11. <action android:name="android.intent.action.MAIN" />
  12. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. <service android:name=".CountService">
  16. <intent-filter>
  17. <action android:name="com.sulang.android.service.Count"></action>
  18. <category android:name="android.intent.category.DEFAULT"></category>
  19. </intent-filter>
  20. </service>
  21. <receiver android:name=".CountServiceBroadcast">
  22. <intent-filter>
  23. <action android:name="com.sulang.android.service.DIVIDE" />
  24. <category android:name="android.intent.category.DEFAULT"></category>
  25. </intent-filter>
  26. </receiver>
  27. </application>
  28. </manifest>

具体效果图如下:

浅谈android Service和BroadCastReceiver的更多相关文章

  1. 浅谈Android保护技术__代码混淆

    浅谈Android保护技术__代码混淆   代码混淆 代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为.将代码中的各种元 ...

  2. 浅谈Android应用保护(一):Android应用逆向的基本方法

    对于未进行保护的Android应用,有很多方法和思路对其进行逆向分析和攻击.使用一些基本的方法,就可以打破对应用安全非常重要的机密性和完整性,实现获取其内部代码.数据,修改其代码逻辑和机制等操作.这篇 ...

  3. 安卓开发_浅谈Android动画(四)

    Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1.  ValueAnimator 基本属 ...

  4. 浅谈Android应用性能之内存

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 文/ jaunty [博主导读]在Android开发中,不免会遇到许多OOM现象,一方面可能是由于开 ...

  5. 浅谈Android五大布局

    Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦.组件按照布局的要求依次排列,就组成了用户所看见的界面.Android的五大布局分别是LinearLay ...

  6. [转]浅谈Android五大布局(二)——RelativeLayout和TableLayout

    在浅谈Android五大布局(一)中已经描述了LinearLayout(线性布局).FrameLayout(单帧布局)和AbsoulteLayout(绝对布局)三种布局结构,剩下的两种布局Relati ...

  7. [转]浅谈Android五大布局(一)——LinearLayout、FrameLayout和AbsoulteLayout

    Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦.组件按照布局的要求依次排列,就组成了用户所看见的界面.Android的五大布局分别是LinearLay ...

  8. 浅谈Android Studio3.0更新之路(遇坑必入)

    >可以参考官网设置-> 1 2 >> Fantasy_Lin_网友评论原文地址是:简书24K纯帅豆写的我也更新一下出处[删除]Fa 转自脚本之家 浅谈Android Studi ...

  9. 浅谈 kubernetes service 那些事(上篇)

    一.问题 首先,我们思考这样一个问题: 访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态.那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知? 二.k8 ...

随机推荐

  1. mysql Alter table设置default的问题,是bug么?

    不用不知道,用了没用? 昨天在线上创建了一个表,其中有两个列是timestamp类型的,创建语句假设是这样的: create table timetest(id int, createtime tim ...

  2. 转:基于InstallShield2013LimitedEdition的安装包制作

    InstallShield Limited Edition for Visual Studio 2013 图文教程(教你如何打包.NET程序)   InstallShield Limited Edit ...

  3. mysql host'XXX' is not allowed to connect to this mysql server

    错误的原因一般是没有添加 IP可远程的权限. 首先以 root 帐户登陆 MySQL 1.在 Windows 主机中点击开始菜单,运行,输入“cmd”,进入控制台,然后cd 进入MySQL 的 bin ...

  4. 7、Django的模型层(1)

    第1节:ORM简介 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极 ...

  5. C/C++常用库及工具

    值得学习的C语言开源项目 - 1. Webbench Webbench是一个在Linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...

  6. screen命令使用

    screen -S + name:创建一个名字叫做name的会话.在里面执行你想要执行的程序,再用Ctrl+a+d退出,让会话Detached,这样就能保证你的任务在后台一直运行,也不会随着终端的关闭 ...

  7. Spring framework3.2整合hibernate4.1报错:No Session found for current thread

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransact ...

  8. C#中XmlSerializer实现序列化浅析

    C# XmlSerializer类是实现序列化的一个类,那么关于C# XmlSerializer的学习我们要掌握怎么样的操作方法呢?那么这里向你详细介绍具体的操作细节情况. C# XmlSeriali ...

  9. python变量的引用,浅拷贝

    python的变量是对象引用 l1和l2引用的相同的对象,所以会相互影响 元组不变的是引用的物理地址,如果引用的对象是可变的,那么远祖也会发生变化 但是t1[2]的id时钟没有发生变化 2 默认是浅拷 ...

  10. Java并发(一)并发编程的挑战

    目录 一.上下文切换 1. 多线程一定快吗 2. 测试上下文切换次数和时长 3. 如何减少上下文切换 4. 减少上下文切换实战 二.死锁 三.资源限制的挑战 四.本章小结 并发编程的目的是为了让程序运 ...