Service 服务
Service: 长期在后台运行没有界面的进程.
- 应用场景
- 监视一个硬件是否被插入
- 连接服务器刷新最新的数据
- 定时对的轮询
注意: 服务是运行在主线程中的,所以不能再服务中进行耗时操作,可以在服务中创建子线程进行耗时操作.
进程的优先级
- Foreground process
前台进程: 用户正在操作的应用程序所在的进程就是前台进程
- Visible process
可视进程: 用户已经不能操作这个应用程序了,但是界面用户仍然可以看到
- Service process
服务进程: 应用程序有一个服务代码正在运行
- Background process
后台进程: 应用程序有界面,但是界面被用户最小化(home)
- Empty process
空进程: 应用程序没有任何运行的Activity,service.
优先级(系统会优先回收优先级较低的进程):
前台进程>可视进程>服务进程>后台进程>空进程
服务的生命周期
- onCreate()--startService()开启服务,服务只会被创建一次,在创建的时候调用onCreate(),一旦服务创建完毕,再去开启服务也不会执行此方法,只会执行
onstart(过时)和onstartcommand()onstart(过时),onstartcommand()- onDestory()--stopService()停止服务,服务只会被停止一次
代码:
1.创建对应的服务类继承Service 2.在清单文件中注册
<service android:name=".DemoService" />
2.在需要的位置开启或关闭服务
/**
* 开启服务
*/
private void start() {
Intent intent = new Intent(this, DemoService.class);
startService(intent);
}
/**
* 关闭服务
*/
private void stop() {
Log.e(TAG, "stop: 点击停止" );
Intent intent = new Intent(this, DemoService.class);
stopService(intent);
}
绑定服务调用服务方法的步骤
虽然可以用startService()开启服务,但是不可以与服务进行通讯,所以使用bindService()可以间接调用服务里面对的方法,与服务进行通讯.
- 步骤
- 定义服务,并在清单文件中注册
public class TestService extends Service{
<service android:name=".TestService" />
- 在服务内定义一个代理人对象MyBinder,在内部定义一个方法,可以调用服务内部方法(为了隐藏服务内部的实现细节,只对外暴露对应的方法,定义一个接口类IService )
public interface IService {
void callMethodInService(String name);
}
public class MyBinder extends Binder implements IService {
//调用服务的内部方法,将来间接与外部进行通讯
@Override
public void callMethodInService(String name) {
//自定义的服务内部的方法
methonInService(name);
}
}
- 在服务实现的Onbind()方法中,将这个代理对象返回.
@Override public IBinder onBind(Intent intent) { return new MyBinder(); }
- 在activity中采用绑定的方式连接服务--bindService()
/**
* 绑定服务
*/
private void bind() {
Intent intent = new Intent(this, TestService.class);
//绑定服务
//new Conn() 通讯频道
//BIND_AUTO_CREATE 如果服务不存在,会把服务创建出来
bindService(intent, new Conn(), BIND_AUTO_CREATE);
}
5.定义bindService()中"通讯频道"这个内部类(new Conn())实现其中的方法
private class Conn implements ServiceConnection {
//当服务连接成功调用的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//private IService mService;
mService = (IService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
6.强制类型转换
mService = (IService) service;
7.调用代理人对象的方法--间接调用了服务里面的方法.
/**
* 调用服务里面的方法
*/
private void method() {
//callMethodInService 服务的中方法
mService.callMethodInService("阿彪");
}
//解绑服务
unbindService(conn);
绑定方式开启服务的生命周期
- 绑定的方式开启服务oncreate->onbind
- 服务的onstart和onstartcommand不会执行
- 解除绑定 unbind-->ondestory
- 多次绑定服务,服务只会创建一次,oncreate只会执行一次
- 多次绑定服务onbind只会执行一次
- 在实际开发中如果需要调用服务中的方式,使用绑定的方式开启服务,只能绑定一次
- 服务只能解绑一次,如果用同一个conn对象对象多次解绑,会抛出异常
两种开启服务方式的比较
- start开启服务
服务一旦开启,长期在后台运行不会随着activity的销毁而停止服务,开启者activity不能调用服务里面玩的方法.
- bind的方式开启服务
如果activity退出了,服务也会跟着停止 开启者(activity)可以间接的调用服务里面的方法
- 混合的方式开启服务
应用场景:为了保证服务仅能长期在后台运行,又能调用服务里面的方法,可以使用混合开启服务的方式,但是因为服务被开启后同时又被绑定,必须要先解除绑定,才能停止服务,因此要想混合开启服务必严格按照以下步骤编写代码:
- start方式开启服务(保证服务长期在后台运行)
- bind的方式绑定服务(为了调用服务的方法)
- unbind的方式解除绑定
- stop 的方式停止服务
本地服务和远程服务
- 本地服务 local service
服务的代码在当前应用程序的内部
- 远程服务 romote service
服务在另一个应用程序里面
进程
进程是操作系统分配的一块独立的内存空间,因此一个程序想要间接调用另一个程序里面的服务的方法,需要进行进程间对的通讯(IPC inter process communication),那么就需要用到aidl(安卓接口定义语言 android interface definition language)来实现进程间对的通讯.
绑定远程服务调用远程服务方法的流程
大致根本地服务的代码是一样的
- 远程服务的接口文件.java-->.aidl
- 把接口定义文件的修饰符删除 public private
- 原来代理人MyBinder extend Binder implemet IService--> extends ISer vice.Stub
- 先把远程服务.aidl文件拷贝到本地应用程序的工程目录里面,包名一致
- iService = IService.Stub.asInterface(service);得到远程服务的代理对象
- 通过代理对象调用远程服务的方法.
- 代码
---创建一个被调用的服务工程
1. 定义服务,并在清单文件中注册,并设置对应的action public class MyService extends Service{ } //添加属性android:exported="true" <service and
roid:name=".MyService"
android:exported="true">
<intent-filter>
<action android:name="com.example.alipay" />
</intent-filter>
</service>
- 创建aidl接口文件 android studio中工程项目 " 右键-->AIDL-->AIDL file" 创建aidl文件 ITestService.aidl
interface ITestService {
int callTestMethodInService(String name);
}
3.在服务中创建对应的代理人对象,并间接调用服务中的方法
//代理人对象
private class MyBind extends ITestService.Stub {
@Override
public int callTestMethodInService(String name) {
//调用服务的方法
return methodInService(name);
}
}
/**
* 服务中的方法
*/
private int methodInService(String name) {
return name.length();
}
--在另外一个项目中调用服务中的方法
- 绑定服务
private void bind() {
Intent intent = new Intent();
// 需要制定action和对应服务的包名,否则会报错
intent.setAction("com.example.alipay");
intent.setPackage("com.example.alipay");
bindService(intent, new Conn(), BIND_AUTO_CREATE);
}
5.将服务中的aidl文件拷贝过来,包名一定要一致!!!,然后build一下工程! 6.创建对应的"通讯频道 conn"
private class Conn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//IService的aidl创建完成之后刷build一下工程
iTestService = ITestService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
7.强制类型转换
iTestService = ITestService.Stub.asInterface(service);
8.调用服务的方法
private void method() {
try {
int hahahah = iTestService.callTestMethodInService("hahahah");
Log.e(TAG, "method: " + hahahah);
} catch (RemoteException e) {
e.printStackTrace();
}
}