相对于应用的界面,Service则是一个看不见的后台。
一个正常的Service需要满足:
- 依附的上下文(必选)
通常是继承自Service,开发者只关心自己需要实现的效果 - 清单的声明(必选)
需要在AndroidManifest.xml中告诉系统存在某个Service。 - 细节的过滤(可选)
可以设置IntentFilter来过滤哪些命令才是Service自己关心的。
Service的正常使用
启动Servie
public ComponentName startService(Intent service)
停止Service
public boolean stopService(Intent name)
//Service中可以调用stopSelf来停止
生命周期
onCreate
onStartCommand //多次启动会回调这个方法
onDestroy
Service的绑定使用
绑定Service
public boolean bindService(Intent service, ServiceConnection conn,int flags)
BindServiceFlags:
- BIND_AUTO_CREATE //只要绑定存在,系统就会自动启动相应的Service
- BIND_DEBUG_UNBIND //调试时方便打印绑定的信息
- BIND_NOT_FOREGROUND //不允许绑定到前台进程
- BIND_ABOVE_CLIENT //如果app被杀,系统尽可能的保留绑定
- BIND_ALLOW_OOM_MANAGEMENT//低内存下尽可能保留绑定
- BIND_WAIVE_PRIORITY//使绑定像后台进程一样被管理
- BIND_IMPORTANT//当客户端是前台进程时,提高其等到同前台进程
- BIND_ADJUST_WITH_ACTIVITY//忽略其他标志,不管其绑定的Activity是否对用户可见,都相应的提高其权重。
解绑Service
public void unbindService(ServiceConnection conn)
生命周期
onCreate
onBind
onUnbind
onDestroy
public interface ServiceConnection {
//当连接到Service时
public void onServiceConnected(ComponentName name, IBinder service);
//当连接的Service宿主出现崩溃或者被杀掉时
public void onServiceDisconnected(ComponentName name);
}
注:
- onCreate只有在Service不存在的时候才会调用
- 如果是通过bindService启动的,调用unbindService会触发销毁,否则只会触发onUnbind,onDestroy则是谁启动的谁关闭,因为系统要确保这个服务最终已经无人使用了。
- 绑定的上下文销毁时Service也会跟着销毁。
IntentService
IntentService本质上是对Service的扩展
优势:
- 为了异步消息处理
- 处理消息后自动停止服务
protected void onHandleIntent(final Intent intent)
开发者只需要关心自己的异步实现就可以了。
AIDL
Android接口定义语言(Android Interface Definition Language)
用来实现跨进程的通讯
跨进程方式 | 对比 |
---|---|
BrodcastReceiver | 实现简单但跨进程比较耗时 |
Messenger | 请求队列是同步进行的,无法并发执行 |
AIDL | 书写稍微麻烦,但是借助工具可以简化,相对Messenger更灵活 |
如果是其他进程提供服务的Service,记得配置Manifest的时候导出
android:process=""//指定进程
android:exported="true"//向外暴露
数据类型
- 基本类型
- Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
- String 类型。
- CharSequence类型。
- List/Map (元素是其他基本类型或parcelable)
- Parcelable
需要写一份对象的aidl,但是只是做声明即可
package xxxPackage;
parcelable xxxClass;
有个bug,可能是不同版本的问题,我这个版本生成的类会调用readFromParcel,而Parcelable已经去掉了该方法,所以对象类中自己手动写了个。
数据流向
adil中非基本参数都需要指明数据流向,不管是 in , out , 还是 inout 。基本参数的定向tag默认是并且只能是 in
- in 服务端只读该参数,不做修改
- out 服务端只对该参数进行修改,不读取传进来的参数
- inout 服务端先读取参数,再对其做修改
可以查看生成的源码,当然其实这个也好理解,上面的基本类型是无法对其地址上的数据做修改的(类似深浅拷贝问题),一般情况下指定in/out即可,没必要做无谓的开销。
总结:其实adil可以看做的bindService的强化版,只需要做以下几步。
- 需要用到自定义的实体,就申明一个实体的aidl,然后写好相应的实体。
- 定义adil接口的方法,如果引用到自定义的类型,就导入相应的类并指定数据流向。
- 在服务端书写Binder继承接口的Stub
- bindService后,在ServiceConnection中获取Binder的实例即可。
网友评论