浅谈android Service和BroadCastReceiver

2024-05-27 04:18

本文主要是介绍浅谈android Service和BroadCastReceiver,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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代码   收藏代码
  1. IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");   
  2. IncomingSMSReceiver receiver = new IncomingSMSReceiver();   
  3. registerReceiver(receiver, filter);   

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

Xml代码   收藏代码
  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的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。 

Java代码   收藏代码
  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绑定服务:

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

   计数服务代码:

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

    计数广播接收者:

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

   manifest文件:

Xml代码   收藏代码
  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.   
  8.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  9.         <activity android:name=".ClientActivity"  
  10.                   android:label="@string/app_name">  
  11.             <intent-filter>  
  12.                 <action android:name="android.intent.action.MAIN" />  
  13.                 <category android:name="android.intent.category.LAUNCHER" />  
  14.             </intent-filter>  
  15.         </activity>  
  16.         <service android:name=".CountService">  
  17.             <intent-filter>  
  18.                 <action android:name="com.sulang.android.service.Count"></action>  
  19.                 <category android:name="android.intent.category.DEFAULT"></category>  
  20.             </intent-filter>  
  21.         </service>  
  22.         <receiver android:name=".CountServiceBroadcast">  
  23.             <intent-filter>  
  24.                 <action android:name="com.sulang.android.service.DIVIDE" />  
  25.                 <category android:name="android.intent.category.DEFAULT"></category>  
  26.             </intent-filter>  
  27.         </receiver>  
  28.     </application>  
  29. </manifest>  

    具体效果图如下:


这篇关于浅谈android Service和BroadCastReceiver的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1006492

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到