1.题记

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

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

2.Service开发详解

服务的开发比较简单,如下:
第一步:继承Service类
publicclassSMSServiceextendsService{}

第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
<serviceandroid: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()方法。
publicclassIncomingSMSReceiverextendsBroadcastReceiver{
@OverridepublicvoidonReceive(Contextcontext,Intentintent){
}
}
第二步:订阅感兴趣的广播Intent,订阅方法有两种:
第一种:使用代码进行订阅

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


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

<receiver android:name=".IncomingSMSReceiver">     <intent-filter>          <action android:name="android.provider.Telephony.SMS_RECEIVED"/>     </intent-filter> </receiver> 

广播被分为两种不同的类型:“普通广播(Normalbroadcasts)”和“有序广播(Orderedbroadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播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)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundlebundle=getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。

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

3.2广播接收者的响应

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

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:
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BATTERY_CHANGED"/>
</intent-filter>
</receiver>

接收开机启动广播Intent在AndroidManifest.xml文件中的<application>节点里订阅此Intent:
<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
并且要进行权限声明:
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

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

<receiverandroid:name=".IncomingSMSReceiver">
<intent-filter>

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

</intent-filter>

</receiver>
在AndroidManifest.xml文件中添加以下权限:
<uses-permissionandroid:name="android.permission.RECEIVE_SMS"/><!--接收短信权限-->
<uses-permissionandroid:name="android.permission.SEND_SMS"/><!--发送短信权限-->

4.简单实例

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

ClientActivity绑定服务:

public class ClientActivity extends Activity {/** Called when the activity is first created. */private ICountService countService;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);this.bindService(new Intent(this, CountService.class),this.serviceConnection, BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {super.onDestroy();this.unbindService(serviceConnection);}@Overridepublic 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() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {countService = (ICountService) service;// 对于本地服务,获取的实例和服务onBind()返回的实例是同一个int i = countService.getCount();Log.v("CountService", "Count is " + i);}@Overridepublic void onServiceDisconnected(ComponentName name) {countService = null;}};}

计数服务代码:

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";@Overridepublic 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; } }

计数广播接收者:

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";@Overridepublic 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 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>

具体效果图如下:


Android之Service&BroadCastReceiver

源代码见附件

更多相关文章

  1. 安装Android studio出现'tools.jar' seems to be not in Android
  2. Android 屏幕旋转后防止重新执行onCreate的方法。
  3. 【Android】‘activity supporting action_view is not set as b
  4. Android中完全退出程序的四种方法
  5. Android Activity启动和退出过程中onResume()方法的回调
  6. andorid跳过系统API获取以太网IP,网关,DNS,MAC的方法
  7. 【Android】关联source code的方法

随机推荐

  1. 业务数据分析
  2. pyinstaller打包总结
  3. aipai服务架构
  4. 量化交易
  5. 关于分库分表后的数据统计异构方案
  6. 已安装nginx动态添加模块
  7. ce内存寻址基址
  8. h5图片展示和ajax上传
  9. downloadonly使用小技巧,快速给无外网系统
  10. vSAN集群 无法识别磁盘处理