Crazy Android Note Chapter-10

第十章 Service与BroadCastReceiver

Service组件的作用和意义
创建、配置Service
启动、停止Service
绑定本地Service并与之通信
Service的生命周期
IntentService的功能和用法
TelephonyManager的功能和用法
监听手机短信
SMSManager的功能和用法
监听手机电话
AudioManager的功能和用法
Vibrator的功能和用法
AlarmManager的功能和用法
BroadcastReceiver组件的功能和意义
开发、配置BroadcastReceiver组件
发送广播、发送有序广播
使用BroadcastReceiver接受系统广播

Service简介

生命周期方法

IBinder onBind(Intent intent):该方法是Service子类必须实现的方法。该方法返回一个IBinder对象,应用程序可通过该对象与Service组件通信。

void onCreate():在该Service第一次被创建后将立即回调该方法

void onDestroy():在该Service被关闭前回调该方法。

void onStartCommand(Intent intent,int flags,int startId):该方法的早期版本是void onStart(Intent intent,int startId),每次客户端调用startService(Intent intent)方法启动该Service时都会回调该方法

boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该方法

在Android中允许Service有两种方式:

    通过Context的startService()方法:通过该方法启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然允许。
    通过Context的bindService()方法:使用该方法启动Service,访问者与Service绑定在一起,访问者一旦退出,Service也终止了。

从Android 5.0开始,Google要求必须使用显示Intent启动Service组件

绑定本地Service并与之通信

当程序通过startService()和stopService()启动、关闭Service时,Service与访问者之前基本不存在太多的关联,因此Service和访问者之间也无法进行通信、交换数据。

如果Service和访问者之间需要进行方法调用或交换数据,则应该使用bindService()和unbindService()
Context的bindService()方法:
    bindService(Intent intent,ServiceConnection conn,int flags)
        intent:该参数通过Intent指定要启动的Service
        conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时将会回调该ServiceConnection对象的onServiceConnected(ComponentName name,IBinder service)方法;当Service所在的宿主进程由于异常终止或其他原因终止,导致Service与访问者之间断开连接时回调该ServiceConnection对象的onServiceDisConnected(ComponentName name)方法。
        flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)
        Note:当调用者主动通过UNBindService()方法断开与Service的连接时,ServiceConnection对象的onServiceDisConnected(ComponentName name)方法并不会被调用

与Service的通信就是通过Service的onBind()返回的IBinder对象,这个IBinder会传给ServiceConnection对象的onServiceConnected方法的IBinder参数。实现通信

对于Service的onBind()方法所返回的IBinder对象来说,它可被当成该Service组件所返回的代理对象,Service允许客户端通过该IBinder对象来访问Service内部的数据,这样既可实现客户端与Service之间的通信

不同启动方式下的Service的生命周期

这里写图片描述

特殊情况:如果Service已由某个客户端通过startService()启动了,接下来其他客户端调用bindService()绑定该Service,在调用unbindService()解除绑定,最后又调用bindService()再次绑定到Service,这个过程触发的生命周期方法:
onCreate() -> onStartCommand() -> onBind() -> onUnbind()(重写该方法时返回true) -> onRebind()

如果希望onRebind()方法被回调,除了需要改Service是由Activity的startService()方法启动之外,还需要Service子重写onUnbind()方法时返回true。

使用IntentService

IntentService是Service的子类,在普通Service上增加了额外的功能
普通Service:

Service不会专门开启一个单独的进程,Service与它所在应用位于同一 进程中
Service不是一条新的线程,因此不应该在Service中进行耗时操作

而IntentService弥补了这些不足:IntentService将会使用队列来管理请求Intent,每当客户端代码通过Intent请求启动IntentService时,IntentService会将该Intent加入队列中,然后开启一个新的worker线程来处理该Intent。对于异步的startService()请求,IntentService会按次序依次处理队列中的Intent,该线程保证同一时刻只处理一个Intent。由于IntentService使用新的worker线程处理Intent请求,因此IntentService不会阻塞主线程,所有IntentService可以处理耗时操作。

IntentService:
会创建单独的worker线程来处理所有的Intent请求
会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无须处理多线程问题
当所有请求处理完成后,IntentService会自动停止,因此无须调用stopSelf()来停止Service
为Service的onBind()提供默认实现,默认实现的onBind()方法返回null
为Service的onStartCommand()方法提供默认实现,该实现会将请求Intent添加到队列中。

所有扩展IntentService实现Service无须重写onBind()、onStartCommand(),只要重写onHandleIntent()即可。

电话管理器(TelephonyManager)

TelephonyManager是一个管理手机通话状态、电话网络信息的服务类,该类提供了大量的getXxx()方法来获取电话网络的相关信息

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

获取手机位置和状态需要声明必要的权限

TelephonyManager除了获取网络状态和SIM卡信息之外,还提供了一个listen(PhoneStateListener listener,int events)来监听通话状态。

短信监听器(SmsManager)

SmsManager是Android提供的另一个常见的服务,SmsManager提供了一些sendXxxMessage()方法用于发送短信,不过通常使用最多的是发送普通文本,就是,sendTextMessage()。

SmsManager sm = SmsManager.getDefault();

发送短信会用到一个PendingIntent对象,PendingIntent是对Intent的封装,一般通过调用PendingIntent的getActivity()、getService()、getBroadcastReceiver()静态方法来获取PendingIntent对象。以Intent不同的是,PendingIntent通常会传给其他应用组件,从而由其他应用程序来执行PendingIntent所包装的”Intent”。

需要添加发短信的权限

音频管理器(AudioManager)

AudioManager am = (AudioManager)getSystemService(Context.Context.AUDIO_SERVICE);

设置手机音频的方法:

adjustStreamVolume(int streamType,int direction,int flags):调整手机指定类型的声音
    streamType:声音类型
        STREAM_ALARM:手机闹铃的声音
        STREAM_DTMF:DTMF音调的声音
        STREAM_MUSIC:手机音乐的声音
        STREAM_NOTIFICATION:系统提示的声音
        STREAM_RING:电话铃声的声音
        STREAM_SYSTEM:手机系统的声音
        STREAM_VOICE_CALL:语音电话的声音

    direction:对声音是增大还是减小;
    flags:调整声音时的标志,例如指定FLAG_SHOW_UI,则调整声音时显示音量进度条

setMicrophoneMute(boolean on):设置是否让麦克风静音
setMode(int mode):设置声音模式,NORMAL、RINGTONE和IN_CALL
setRingerMode(int ringerMode):设置手机的电话铃声模式
    RINGER_MODE_NORMAL:正常的手机铃声
    RINGER_MODE_SILENT:手机铃声静音
    RINGER_MODE_VIBRATE:手机震动

setSpeakerphoneOn(boolean on):设置是否打开扩音器
setStreamMute(int streamType,boolean state):将手机的指定类型调整为静音,其中streamType与上面的相同
setStreamVolume(int streamType,int index,int flags):直接设置手机的指定类型的音量值

振动器(Vibrator)

Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

vibrate(long milliseconds):控制手机震动毫秒
vibrate(long[] pattern,int repeat):指定手机里pattern指定的模式振动。
    例如:pattern为new int[400,800,1200,1600],就是指定在400ms,800ms,1200ms,1600ms这些时间点交替启动、关闭手机振动器;其中repeat指定pattern数组的索引,指定对pattern数组中从repeat索引开始的振动进行循环
cancel():关闭手机振动

手机闹钟服务(AlarmManager)

AlarmManager通常的用途是用来开发手机闹钟,但实际上它的作用不止于此。它的本质是一个全局定时器,AlarmManager可在指定时间或指定周期启动其他组件(包括Activity、Service、BroadcastReceiver).

set(int type,long triggerAtTime,PendingIntent operation):设置在triggerAtTime时间启动由operation参数指定的组件,
    type:指定定时服务的类型
        ELAPSED_REALTIME:指定从现在开始时间过了一定时间后启动operation所对应的组件
        ELAPSED_REALTIME_WAKEUP:指定从现在开始时间过了一定时间后启动operation所对应的组件。即使系统处于休眠状态也会执行operation所对应的组件
        RTC:指定当系统调用System.currentTimeMillis()方法的返回值与triggerAtTime相等时启动operation所对应的组件
        RTC_WAKEUP:指定当系统调用System.currentTimeMillis()方法的返回值与triggerAtTime相等时启动operation所对应的组件。即使系统处于休眠状态也会执行operation所对应的组件。

setInexactRepeating(int type,long triggerAtTime,long interval,PendingIntent operation):设置一个非精确的周期性任务。例如,我们设置Alarm每个小时启动一次,当系统并不一定总在每个小时的开始启动Alarm服务。
setRepeating(int type,long triggerAtTime,long interval,PendingIntent operation):设置一个周期性执行的定时任务
cancel(PendingIntent operation):取消AlarmManager的定时服务。

Note:从Android 4.4(API 19)开始,AlarmManager的机制是非准确激发的,操作系统柜偏移(shift)闹钟来最小化唤醒和电池消耗。不过AlarmManager新增了两个方法支持精确激发:

setExact(int type,long triggerAtMillis,PendingIntent operation):设置闹钟将在精确的时间被激发。
setWindow(int type,long windowStartMillis,long windowLengthMillis,PendingIntent operation):设置闹钟将在精确的时间段内被激发。

对于targetSdkVersion在API 19之前的应用仍将继续使用以前的行为,所以闹钟都会使用精确激发。

广播

BroadcastReceiver本质上就是一个全局监听器,用于监听系统全局的广播消息。由此它可以非常方便的实现系统中不同组件之间的通信。

程序启动BroadcastReceiver只需两步:

创建需要启动的BroadcastReceiver的Intent
调用Context的sendBroadcast()或sendOrderBroadcast()方法启动指定的BroadcastReceiver。

当程序发出一个Broadcast Intent之后,所有匹配该Intent的BroadcastReceiver都有可能被启动

Note:其他类似OnXxxListener属于程序级别的监听器,这些监听器运行在指定程序所在的进程中,当程序退出时,onXxxListener监听器就随之关闭了。但是BroadcastReceiver属于系统级别的监听器,它拥有自己的进程,只要存在与之匹配的Intent广播出来,BroadcastReceiver就会被激发。

一旦实现了BroadcastReceiver,接下来就应该指定该BroadcastReceiver能匹配的Intent,有两种方式:

使用代码指定:调用Context的registerReceiver(BroadcastReceiver receiver,IntentFilter filter)方法指定

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

在Manifest.xml文件中配置:

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

BroadcastReceiver的onReceive()方法如果不能再10秒内执行完成,Android就会认为程序无响应,所以onReceive()方法不能执行耗时操作。

如果需要根据Broadcast执行一项耗时的操作,应该考虑通过Intent启动Service来完成,不应该考虑使用新线程去完成耗时操作,因为BroadcastReceiver本身的生命周期很短, 可能出现的情况是子线程可能还没结束,BroadcastReceiver就已经退出了。
如果BroadcastReceiver所在的进程结束了,虽然该进程内还有用户启动的新线程,但由于该进程内不包含任何活动组件,因此系统可能在内存紧张时优先结束该进程。这样就可能导致BroadcastReceiver启动的子线程无法执行完成。

普通广播(Normal Broadcast)

完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递效率高,缺点是接收者不能处理结果传递给下一个接收者,无法终止Broadcast Intent的传播

有序广播(Ordered Broadcast)

接收者将按预先声明的优先级依次接收Broadcast。优先级声明在<intent-filter.../>元素的android:priority属性中,数值越大优先级越高,取值范围为-1000~1000,

Context提供如下两个方法用于发送广播:

sendBroadcast():发送Normal Broadcast

sendOrderedBroadcast():发送Ordered Broadcast

对于Ordered Broadcast而言,优先接收到Broadcast的接收者可以通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,然后传给下一个接收者,下一个接收者通过Bundle bundle = getResultExtras(true) 可以获取上一个接收者存入的数据。

Note:系统收到短信,发出的Broadcast属于Ordered Broadcast。如果想阻止用户受到短信,可以通过设置优先级,让自定义的BroadcastReceiver先获取到Broadcast,然后终止Broadcast。

接收系统广播

除了接收用户发送的广播外,BroadcastReceiver还有一个重要的用途:接收系统广播。

ACTION_TIME_TICK:当前时间改变,每分钟发送一次,
ACTION_TIME_CHANGED:系统时间被改变
ACTION_TIMEZONE_CHANGED:系统时区被改变
ACTION_BOOT_COMPLETED:系统启动完成
ACTION_PACKAGE_ADDED:系统添加包
ACTION_PACKAGE_CHANGED:系统包改变
ACTION_PACKAGE_REMOVED:系统包被移除
ACTION_PACKAGE_RESTARTED:系统包被重启
ACTION_PACKAGE_DATA_CLEARED:系统包数据被清空
ACTION_UID_REMOVED:UID被移除
ACTION_BATTERY_CHANGED:电量变化
ACTION_POWER_CONNECTED:系统连接电源
ACTION_POWER_DISCONNECTED:系统与电源断开
ACTION_SHUTDOWN:系统被关闭

Note:以上的Action有些只能通过代码注册的方式才能被接收到,不能在Manifest.xml中注册

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值