异步消息处理基本用法
- 准备
int常量
用于标记某个任务
; - 主线程实例化
Handler对象
,
同时重写Handler
的handleMessage()
方法,
方法中通过使用if
或者switch
,
将(子线程发送的)Message
的what
字段
同一个或者以上的int任务标志常量
做匹配,
调用对应的任务处理模块
进行处理;
- 在对应的场景(如某个View的回调方法中):
利用匿名类的方式,通过Thread、Runnable()、run()、start()
等类与方开启子线程,在子线程的线程任务执行单位(即run()
)中:
3.1. 实例化Message
对象;
3.2. 将任务常量id
设置到Message
实例对象的what
字段中;
3.3. 使用2.中定义的Handler
实例调用sendMessage()
将Message
实例发送到MQ
;
至此完成;
- 相关笔记:Tip | Android的消息机制
Service生命周期
onCreate()
:服务第一次被创建时调用onStartComand()
:服务启动时调用onBind()
:服务被绑定时调用onUnBind()
:服务被解绑时调用onDestroy()
:服务停止时调用
普通Service(开启Service的两个基本方法,其一)
- 新建一个类并令其继承Service且必须重写
onBind()
方法,
有选择的重写onCreate()、onStartCommand()
及onDestroy()
方法;
- 在配置文件中进行注册;
或者直接按照以下方法则AS会自动注册:
- 在对应的场景(如某个View的回调方法中),
利用Intent可实现Service的启动:
Intent intent = new Intent(this, MyService.class);// MyService是刚刚定义好的Service
startService(intent);
Service的停止:
Intent intent = new Intent(this, MyService.class);
stopService(intent);
Service与Activity的通信(开启Service的两个基本方法,其二)
- 新建一个
类(如MyService)
继承自Service
并注册
好; - 类中定义一个
内部类(如MyBinder)
继承Binder
,
在其内部编写要放在Service后台服务
执行的逻辑方法模块;
- 在
继承自Service
的类(MyService)
中
实例化继承Binder的内部类(MyBinder)实例
并作为MyService
的成员变量;
- 重写
onBind()
方法,返回成员变量MyBinder实例
; - 在对应
启动Service
的活动
中,
在活动中实例化一个ServiceConnection类
对象,
并重写它的onServiceConnection()
和onServiceDisconnection()
方法,
这两个方法分别会在活动与服务成功绑定
以及解除绑定
的时候调用。
在onServiceConnected()
方法中,
又通过向下转型得到了MyBinder
的实例,
有了它就可以在活动中
调用MyBinder中
的任何非private方法了
,
即实现Service与Activity的通信
。
- 最后在在对应的场景(如某个View的回调方法中),
利用Intent对象以及下面两个方法
实现活动和服务的绑定和解绑:
bindService()
实现绑定
,
它接收三个参数(Intent对象,ServiceConnection对象,标志位
),
这里传入BIND_AUTO_CREATE
表示在活动和服务进行绑定后自动创建服务
,
unbindService(
)实现解绑
,
传入ServiceConnection
对象即可。
前台Service
前台Service类似通知,
只不过在构建好一个Notification
之后,
不需要NotificationManager
将通知显示出来,
而是调用了startForeground()
方法。
可以在新建的继承Service
的类的onCreate()
方法中,如下编写:
启动方法同普通Service,即在对应的场景(如某个View的回调方法中)编写:
Intent intent = new Intent(this, MyService.class);// MyService是刚刚定义好的Service
startService(intent);
系统Service
除了自定义一个Service
,可以使用现有的系统服务
;
通过getSyetemService()
方法并传入一个Name
即可得到相应的服务对象,
常用的系统服务如下表:
下面学习AlarmManager
系统服务,实现一个后台定时任务
调用AlarmManager
的set()
方法就可以设置一个定时任务
,set()
有三个参数(工作类型,定时任务触发的时间,PendingIntent对象)
:
1)工作类型
:有四个值
可选:
2)定时任务触发的时间
:以毫秒
为单位,传入值
和第一个参数
对应关系:
3)PendingIntent对象
:
一般会调用它的getBroadcast()
方法来获取一个能够执行广播的PendingIntent
。
这样当定时任务被触发的时候,
广播接收器中的onReceive()
方法即可得到执行,
在onReceive()
方法我们可以再次启动Service
,
同时编写任务执行代码块;
实战使用时,
可以在新建的继承Service
的类的onStartCommand()
方法中,
如下编写:
注意这里的提供给PendingIntent
的Intent
跳转到的广播接收器
是需要我们自己定义的
,
这里定义的接收器是MyBroadcast
:
如此一来,
一旦启动MyService
,
就会在onStartCommand()
方法里设定一个定时任务
,10秒
后MyReceiver
的onReceive()
方法将被回调执行,
紧接着又反过来启动MyService
,反复循环。
从而实现一个能长期在后台进行定时任务的服务。
同时在MyReceiver
的onReceive()
方法中
我们可以添加编写任务执行代码块
;
另外,从Android 4.4
版本开始,
由于系统在耗电性方面进行了优化使得Alarm任务的触发时间会变得不准确。
如果一定要求Alarm任务的执行时间精确,
把AlarmManager
的setExact()
方法替代set()
方法就可以了。
IntentService
使用Android提供的IntentService,
可以简单地实现一个异步的、会自动停止的服务;
- 新建类并继承
IntentService
,
类中提供一个无参的构造函数
且必须在其内部
调用父类的有参构造函数
;
然后重写onHandleIntent()
方法,
里面可以处理一些耗时操作而不用担心 ANR的问题,
因为这个方法已经是在子线程中运行的了。
- 在配置文件中进行注册。
- 在活动中利用
Intent
启动IntentService
,同普通Service。
实战参考:
onHandleIntent()
方法中为了证实这个方法确实已经在子线程中,
打印了当前线程的id
与稍后与主线程的线程id
作对比。
另外,IntentService的特性是在运行结束后应该是会自动停止
,
这里重写onDestroy()
方法在其中打印一行日志,
证实服务是不是停止掉
了。
接着注册:或者直接按照以下方法则AS会自动注册:
在对应的场景(如某个View的回调方法中),
利用Intent可实现Service的启动,同普通Service:在这里打印了
主线程的 id
,
用于同方才说的IntentService
中onHandleIntent()
方法中打印的线程id
进行对比;