前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈android Service和BroadCastReceiver

浅谈android Service和BroadCastReceiver

作者头像
郭耀华
发布2018-05-09 11:11:12
2K0
发布2018-05-09 11:11:12
举报
文章被收录于专栏:郭耀华‘s Blog郭耀华‘s Blog

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,订阅方法有两种:  第一种:使用代码进行订阅

Java代码  

代码语言:javascript
复制
 IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");   
 IncomingSMSReceiver receiver = new IncomingSMSReceiver();   
 registerReceiver(receiver, filter);   

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

Xml代码  

代码语言:javascript
复制
 <receiver android:name=".IncomingSMSReceiver"> 
  <intent-filter> 
  <action android:name="android.provider.Telephony.SMS_RECEIVED"/> 
  </intent-filter> 
 </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的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。 

Java代码  

代码语言:javascript
复制
 public class IncomingSMSReceiver extends BroadcastReceiver {   
  @Override public void onReceive(Context context, Intent intent) {   
  //发送Intent启动服务,由服务来完成比较耗时的操作  
             Intent service = new Intent(context, XxxService.class);   
             context.startService(service);   
     }   
 }   

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绑定服务:

Java代码  

代码语言:javascript
复制
 public class ClientActivity extends Activity {  
  /** Called when the activity is first created. */ 
  private ICountService countService;  
  
  @Override 
  public void onCreate(Bundle savedInstanceState) {  
  super.onCreate(savedInstanceState);  
         setContentView(R.layout.main);  
  this.bindService(new Intent(this, CountService.class),  
  this.serviceConnection, BIND_AUTO_CREATE);  
     }  
  
  @Override 
  protected void onDestroy() {  
  super.onDestroy();  
  this.unbindService(serviceConnection);  
     }  
  @Override 
  public boolean onKeyUp(int keyCode, KeyEvent event) {  
  if(keyCode==KeyEvent.KEYCODE_BACK)  
         {  
  this.unbindService(serviceConnection);  
  this.finish();  
  return true;  
         }  
  return super.onKeyUp(keyCode, event);  
     }  
  private ServiceConnection serviceConnection = new ServiceConnection() {  
  @Override 
  public void onServiceConnected(ComponentName name, IBinder service) {  
             countService = (ICountService) service;// 对于本地服务,获取的实例和服务onBind()返回的实例是同一个 
  int i = countService.getCount();  
             Log.v("CountService", "Count is " + i);  
         }  
  
  @Override 
  public void onServiceDisconnected(ComponentName name) {  
             countService = null;  
         }  
     };  
  
 }  

   计数服务代码:

Java代码  

代码语言:javascript
复制
 package com.sulang.android.service;  
  
 import android.app.Service;  
 import android.content.Intent;  
 import android.os.Binder;  
 import android.os.IBinder;  
 import android.util.Log;  
  
 /* 
  *@author 七里香的悔恨,2011-3-17 
  *CountService.java 
  *Blog:[url]http://bigboy.iteye.com/[/url] 
  */ 
 public class CountService extends Service {  
  private boolean quit=false;   
  private int count;   
  private ServiceBinder serviceBinder = new ServiceBinder();   
  private final static String DIVIDE_RESULT="com.sulang.android.service.DIVIDE";  
  @Override 
  public IBinder onBind(Intent intent) {  
  return serviceBinder;   
     }  
  public class ServiceBinder extends Binder implements ICountService {   
  @Override 
  public int getCount() {   
  return count;   
         }   
     }   
  @Override 
  public void onCreate() {   
  super.onCreate();   
  new Thread(new Runnable() {   
  @Override 
  public void run() {   
  while (!quit) {   
  try {   
                     Thread.sleep(1000);   
                     } catch (InterruptedException e) {}   
                     count++;   
  if(count%5==0)  
                     {  
                         Intent intent = new Intent(DIVIDE_RESULT);  
                         intent.putExtra("count", count);  
                         sendBroadcast(intent);  
                     }  
                     Log.i("CountService", count+"");  
                 }   
             }   
         }).start();   
     }   
  
  @Override 
  public void onDestroy() {   
  super.onDestroy();   
  this.quit = true;   
     }   
  
 }  

    计数广播接收者:

Java代码  

代码语言:javascript
复制
 package com.sulang.android.service;  
  
 import android.content.BroadcastReceiver;  
 import android.content.Context;  
 import android.content.Intent;  
 import android.widget.Toast;  
  
 /* 
  *@author 七里香的悔恨,2011-3-18 
  *CountServiceBroadcast.java 
  *Blog:[url]http://bigboy.iteye.com/[/url] 
  */ 
 public class CountServiceBroadcast extends BroadcastReceiver {  
  private final static String DIVIDE_RESULT="com.sulang.android.service.DIVIDE";  
  @Override 
  public void onReceive(Context context, Intent intent) {  
         String action = intent.getAction();  
  if(action.equals(DIVIDE_RESULT))  
         {  
  int count = intent.getIntExtra("count", 0);  
             Toast.makeText(context, "当前数字为:"+count, Toast.LENGTH_LONG).show();  
         }  
     }  
  /** 
      * 使用代码进行订阅广播 
      * IntentFilter filter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); 
      * IncomingSMSReceiver receiver=new IncomingSMSReceiver(); 
      * registerReceiver(receiver,filter); 
      */ 
  
 }  

manifest文件:

Xml代码  

代码语言:javascript
复制
 <?xml version="1.0" encoding="utf-8"?> 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  package="com.sulang.android.service" 
  android:versionCode="1" 
  android:versionName="1.0"> 
  <uses-sdk android:minSdkVersion="4" /> 
  
  <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  <activity android:name=".ClientActivity" 
  android:label="@string/app_name"> 
  <intent-filter> 
  <action android:name="android.intent.action.MAIN" /> 
  <category android:name="android.intent.category.LAUNCHER" /> 
  </intent-filter> 
  </activity> 
  <service android:name=".CountService"> 
  <intent-filter> 
  <action android:name="com.sulang.android.service.Count"></action> 
  <category android:name="android.intent.category.DEFAULT"></category> 
  </intent-filter> 
  </service> 
  <receiver android:name=".CountServiceBroadcast"> 
  <intent-filter> 
  <action android:name="com.sulang.android.service.DIVIDE" /> 
  <category android:name="android.intent.category.DEFAULT"></category> 
  </intent-filter> 
  </receiver> 
  </application> 
 </manifest> 

    具体效果图如下:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-02-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.题记
  • 2.Service开发详解
  • 3.BroadcastReceiver开发详解
    • 3.1BroadcastReceiver广播接收者
      • 3.2广播接收者的响应
        • 3.3常见系统广播接收者
        • 4.简单实例
        相关产品与服务
        短信
        腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档