安卓基础8:服务
服务:
(在后台运行)
进程:
是安卓应用的载体,4大组件均在进程中运行,更准确的说是在主线程中运行。当系统内存不足时,会移除一些旧进程给新的进程。
主线程:
只要不新建线程,都属于主线程上运行;主线程不能够执行耗时操作,需要额外开辟线程运行
进程层级:
ForeGround process:前台进程;
相当于activity执行了onresume方法,用户正在操作该进程界面
Visible process:可视进程;
没有前台组件,但是影响用户使用的界面
Eg:透明应用
透明应用在被部署之后会走onpause方法;
Service process:服务进程;
通过startService开启了一个服务;
Eg:音乐播放器,再后退之后在后台播放音乐
Background process:后台进程
相当于activity执行了onstop方法;(点home键);用户不可见其界面
Empty process:空进程
后台没有任何组件运行;相当于退出应用,仅仅是留了线程在上面(目的:为了下次再载入时速度能快一些)
服务:
Activity 和 service都继承ContextWrapper;两个要复写的方法都相似,只是与界面相关的方法,service都没有;
服务通过startService()开启服务,在界面退出之后,服务会在后太长时间运行,最终通过调用stopServce()关闭服务;
服务调用方法顺序:
服务第一次开启时:
调用:onCreate()方法
服务第二次开启时:
调用:onStartCommand()方法;
当服务关闭时:
调用onDestroy();
电话窃听器案例:
(通过广播开启服务)
布局填充器:
实现步骤:
1、 定义一个服务
2、 在服务的oncreate方法中创建TelephonManager的实例,可以通过这个类可以监听电话的状态;
3、 定义一个类,myPhoneStateListener用来监听电话的状态,并通过MediaRecoder类实现录音的功能;
4、 广播中开启服务
5、 在清单文件加上响应的文件
代码
描述:
1、 通过广播来监听接听电话事件
2、 通过一个服务长期运行,监听电话状态
3、 当处于响铃状态,准备录音
4、 当处于接听状态,开始录音
代码:
事件处理:
通过广播启动监听:
电话服务:
配置清单:
使用服务注册特殊的广播接收者
(通过服务开启广播)
描述:
在开机之后去启动服务注册开屏、锁屏广播事件;并接收该广播事件
代码:
事件处理
开启服务
服务中创建开屏、关屏广播事件
监测广播事件
配置清单:
通过bind方式开启服务的生命周期
Bind开启服务特点:
1、 第一次点击按钮,通过bindservice开启服务,服务只会走oncreate和onbind方法;
2、 关闭app之后,第二次点击按钮,服务不执行;因为,服务已经被杀死了;
3、 “不求同时生,只求同时死”:bind开启的服务,随着主界面消亡而消亡
4、 服务只能解绑一次,再解绑会报异常;同时,绑定谁,解绑的时候就是谁
5、 通过bindservice开始的服务,在进程设置页面找不到,可以理解为隐形的服务
6、 当服务的onbind返回为空时onServiceConnected()方法不执行
直接new出服务对象时,不再是服务,而是普通的对象,不再有上下文对象
步骤:
1、 定义一个服务,并配置清单文件
2、 Activity想调用服务中的方法
3、 在服务的内部定义一个中间人对象即Ibinder的实现类(在这个实现类中可以间接调用到服务的方法)
4、 在onbind方法中将自己定义的中间人对象返回
5、 当Activity想要调用服务时,先通过onServiceConnected可以获取中间人对象
6、 通过中间人对象我们就可以调用我们想要的方法
通过bind启动服务后执行顺序
在服务第一次先执行时:onCreate
当服务被绑定调用时:onBind
当服务被销毁时调用:onDestroy
当服务再次被启动时:onStartCommand
代码
事物处理
主界面通过bind启动服务
任务执行过程:
配置清单:
通过BinderService对象获取服务内容
在之前通过startService启动服务,执行的是服务中指定的程序;我们期望获取服务中的方法,手动调用服务中的一些方法,因此用Binderservice;
执行过程:
1、 创建一个检测服务的对象,实现serviceConnextion
2、 利用bindService去连接服务
3、 在服务中创建继承binder的中间对象,里面放上我想要调用的方法;
4、 通过任务的onBind方法将中间对象提交给serviceConnextion的onServiceConnected方法,然后再去调相应的想用的方法
代码:
描述:
想办事不能直接找领导,我们通过中间人去求领导办事
事务处理:
服务层:
配置清单:
抽取中间对象Binder中的方法为接口
接口可以隐藏代码内部的细节,暴露程序员想要暴露的方法;
步骤:
1、 定义一个接口,暴露程序员想要暴露的方法;
2、 我们定义的这个中间人对象实现我们的接口的方法
3、 用过bindservice方法获取我们中间人对象
4、 通过中间人对象调用服务里面的方法
代码
事务处理层:
服务层:
接口
配置清单:
百度音乐盒:
需求:我们既想让服务子在后台长期运行,又想调用服务中的方法
通过startService方法不能调用方法;通过bindservice方法不能长期运行,因此我们需要通过混合方法区实现;
startService
bindService
unbindService
stopService
开启的先后顺序:
1、 必须先startService方法,能够在后台长期运行
2、 调用bindservice方法,能够邦正调用服务中的方法
3、 调用unbindService方法,解绑服务
4、 Stopservice现在大多数app都不调用这个方法
代码:
描述:
建立一个播放器,通过点击里面的播放、暂停按钮去调用服务中的方法
事务处理层:
服务层:
接口层:
配置清单:
AIDL(android interface Definition Languge)
基本概念
本地服务:运行在自己应用里面的服务
远程服务:运行在其他应用里面的服务
本地服务与远程服务间通信称为进程间通信;
AIDL解决的问题:进程间的通信
AIDL实现步骤:
1、 在一个应用里面定义一个服务,服务里面有一个方法,这个方法称为远程服务的方法
2、 在这个服务里面定义中间人对象,定义接口iservice.java把想暴露的方法定义在接口中
3、 把iservice.java文件改为aidl文件,注意:aidl不支持public
4、 系统会自动给我们生成一个iservice.java文件
public static abstractclass Stub extends android.os.Binderimplementscom.itheima.remoteservice.Iservice
5、 把我们定义的中间人对象直接继承Stub
6、 我想在另一个应用里面去调用这个服务里面的方法要保证使用同一个aidl文件
7、 若要保证aidl文件相同,谷歌要求包名相同
8、 在本地服务中,还是通过bindservice方法去获取中间人对象
9、 注意获取我们定义的中间人对象的方式不一样,通过stub的一个静态方法区获取我们定义的中间人对象Stub.ainterface(Ibinder obj);
远程端代码:
服务:
接口:
配置清单:
本地代码:
事务处理:
通过AIDL,在本地会生成一个对应的stub
AIDL应用场景:
支付宝:
事务处理层:
接口层:
清单配置
欢乐斗地主:
事务处理层: