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. python字典的基本操作

    字典的基本方法 什么是字典: 字典是一种 key - value的数据类型,听alex说就像我们上学用的字典,通过笔划,字母来查找对饮页面的详细内容. 语法: id_dict = { 'stu1101 ...

  2. MySQL报错:error1130

    ERROR (HY000): Host 'ip-172-31-x-x.ec2.internal' is not allowed to connect to this MySQL server 分析,从 ...

  3. 记录一次向TiDB数据库导入数据的例子

    导出数据 今天从Mysql的某个库中导出一个表大概有20分钟吧,等了一会终于导出成功了.查看一下文件的大小: [tidb@:vg_adn_CkhsTest ~]$du -h ./creative_ou ...

  4. sql注入--基础

    什么是sql注入: 利用SQL语句 在外部 对数据库进行 查询,更新等 动作 sql注入的原理: 输入值可控且带入数据库执行(前提) 接受的变量传值未进行过滤(实质) sql注入的目的: 获取数据(网 ...

  5. 漏洞扫描--openvas

    操作实例演示 0.登录openvas 点击“openvas start”启动openvas相关服务,服务启动成功之后!在浏览器输入网址:https://127.0.0.1/login/login.ht ...

  6. initialProps被React-Navigation的navigation属性覆盖解决方案

    怎么开场对我来说一个是个很纠结的问题,Emmm这应该算个好开场. 最近在做一个RN的app端调试工具,在把它嵌入原生app中的时候遇到了一个问题,RN组件里面接受不到原生传过来的initialProp ...

  7. Spring-IOC 扩展点 BeanFactoryPostProcessor及其子接口解析

    BeanFactoryPostProcessor 接口的英文描述: Allows for custom modification of an application context's bean de ...

  8. Scala学习之路 (九)Scala的上界和下届

    一.泛型 1.泛型的介绍 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性.泛型的典型应用场景是集合及集合中 ...

  9. 集成Glide4.3.1出错!AbstractMethodError: abstract method "void com.bumptech.glide.module

    项目中原本是用的Glide3.7.0,一切功能正常,但是集成了网易云信的UIKIT后,就出问题了,发现是Glide4.0的问题. Glide4.0,始终会报这么一个错,就算是最简单的加载也仍然报错. ...

  10. JS图片灯箱(lightBox)效果基本原理和demo

    到年底了,项目不怎么忙,所以有空特地研究了下KISSY中源码JS灯箱效果,感觉代码比较简单,所以就按照他们的思路依赖于Jquery框架也封装了一个,特地分享给大家,以前经常看到网上很多这样的插件,感觉 ...