鸿蒙开发之Service Ability
1.基本概念
基于Service模板的Ability(简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动,即使用户切换到其他应用,Service仍将在后台继续运行。
1.Service是单实例的。在一个设备上,相同的Service只会存在一个实例。
2.如果多个Ability共用这个实例,只有当与Service绑定的所有Ability都退出后,Service才能够退出。
3.由于Service是在主线程里执行的,因此,如果在Service里面的操作时间过长,必须在Service里创建新的线程来处理,防止造成主线程阻塞,应用程序无响应。
2.创建Service
创建Ability的子类,实现Service相关的生命周期方法。Service也是一种Ability,Ability为Service提供了以下生命周期方法,用户可以重写这些方法来添加自己的处理。
包上右键选择New => Ability => Empty Service Ability创建一个ServiceAbility1
public class ServiceAbility1 extends Ability {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001101, "ServiceAbility1");
@Override
public void onStart(Intent intent) {
HiLog.error(LABEL_LOG, "--------ServiceAbility1::onStart");
super.onStart(intent);
}
@Override
public void onBackground() {
super.onBackground();
HiLog.info(LABEL_LOG, "--------ServiceAbility1::onBackground");
}
@Override
public void onStop() {
super.onStop();
HiLog.info(LABEL_LOG, "--------ServiceAbility1::onStop");
}
/**
* 每次调用ServiceAbility1都会执行该方法
* @param intent 数据载体
* @param restart 启动状态 true:销毁后启动,false:正常启动
* @param startId 启动的计数器
*/
@Override
public void onCommand(Intent intent, boolean restart, int startId) {
HiLog.info(LABEL_LOG, "--------ServiceAbility1::onCommand");
System.out.println("数据载体:"+intent.getOperation().getAbilityName());
System.out.println("启动状态:"+restart);
System.out.println("启动的计数器:"+startId);
}
@Override
public IRemoteObject onConnect(Intent intent) {
return null;
}
@Override
public void onDisconnect(Intent intent) {
}
}
2.注册Service
Service也需要在应用配置文件中进行注册,注册类型type需要设置为service。
{
"module": {
"abilities": [
{
"name": "com.example.myapplication.ServiceAbility1",
"icon": "$media:icon",
"description": "$string:serviceability1_description",
"type": "service"
},
]
...
}
...
}
3.启动Service
Ability为开发者提供了startAbility()方法来启动另外一个Ability。因为Service也是Ability的一种,开发者同样可以通过将Intent传递给该方法来启动Service。不仅支持启动本地Service,还支持启动远程Service。
启动Service主要用于启动一个服务执行后台任务或者远程启动一个功能,不进行通信,如设备A让设备B播放音乐。
可以通过构造包含DeviceId、BundleName与AbilityName的Operation对象来设置目标Service信息。
DeviceId:表示设备ID。如果是本地设备,则可以直接留空;如果是远程设备,可以通过ohos.distributedschedule.interwork.DeviceManager提供的getDeviceList获取设备列表。
BundleName:表示包名称。
AbilityName:表示待启动的Ability名称。
Layout_ability_main布局xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:orientation="vertical">
<Button
ohos:id="$+id:button1"
ohos:width="match_content"
ohos:height="match_content"
ohos:background_element="$graphic:background_button"
ohos:text="启动本地设备的Service"
ohos:layout_alignment="horizontal_center"
ohos:text_size="100"/>
<Button
ohos:id="$+id:button2"
ohos:width="match_content"
ohos:top_margin="100px"
ohos:height="match_content"
ohos:background_element="$graphic:background_button"
ohos:text="停止本地设备的Service"
ohos:layout_alignment="horizontal_center"
ohos:text_size="100"/>
</DirectionalLayout>
背景xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<corners
ohos:radius="10"/>
<solid
ohos:color="#007CFD"/>
</shape>
启动本地设备Service
config.js配置分布式权限
"reqPermissions": [
{"name": "ohos.permission.DISTRIBUTED_DATASYNC"},
{"name": "ohos.permission.servicebus.ACCESS_SERVICE"},
{"name": "com.huawei.hwddmp.servicebus.BIND_SERVICE"},
{"name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"},
{"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO" },
{"name": "ohos.permission.GET_BUNDLE_INFO"}
]
显示声明需要使用的权限
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC",
"ohos.permission.servicebus.ACCESS_SERVICE",
"com.huawei.hwddmp.servicebus.BIND_SERVICE"}, 0);
}
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00002, "MainAbilitySlice");
/**
* 启动本地设备的Service
* @param intent
*/
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
Button button1 = (Button) findComponentById(ResourceTable.Id_button1);
button1.setClickedListener(component -> {
//构造包含DeviceId、BundleName与AbilityName的Operation对象来设置目标Service信息
Intent intent1 = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.myapplication")
.withAbilityName("com.example.myapplication.ServiceAbility1")
.build();
intent1.setOperation(operation);
startAbility(intent1);
});
}
}
启动远程设备Service
/**
* 启动本地设备的Service
* @param intent
*/
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//获取设备列表
List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
if(deviceList.isEmpty()){
return ;
}
int deviceNum = deviceList.size();
List<String> deviceIds = new ArrayList<>(deviceNum);
List<String> deviceNames = new ArrayList<>(deviceNum);
deviceList.forEach((device)->{
deviceIds.add(device.getDeviceId());
deviceNames.add(device.getDeviceName());
});
//使用deviceIds的第一个元素,做为启动远程设备的目标id
String devcieIdStr = deviceIds.get(0);
Button button1 = (Button) findComponentById(ResourceTable.Id_button1);
button1.setClickedListener(component -> {
//构造包含DeviceId、BundleName与AbilityName的Operation对象来设置目标Service信息
Intent intent1 = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId(devcieIdStr)
.withBundleName("com.example.myapplication")
.withAbilityName("com.example.myapplication.ServiceAbility1")
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE) // 设置支持分布式调度系统多设备启动的标识
.build();
intent1.setOperation(operation);
startAbility(intent1);
});
}
Ability将通过startAbility() 方法来启动Service。
如果Service尚未运行,则系统会先调用onStart()来初始化Service,再回调Service的onCommand()方法来启动Service。
如果Service正在运行,则系统会直接回调Service的onCommand()方法来启动Service。
4.停止Service
Service一旦创建就会一直保持在后台运行,除非必须回收内存资源,否则系统不会停止或销毁Service。开发者可以在Service中通过terminateAbility()停止本Service或在其他Ability调用stopAbility()来停止Service。
停止Service同样支持停止本地设备Service和停止远程设备Service,使用方法与启动Service一样。一旦调用停止Service的方法,系统便会尽快销毁Service。
停止本地设备Service
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00002, "MainAbilitySlice");
/**
* 停止本地设备的Service
* @param intent
*/
@Override
public void onStart(Intent intent) {
HiLog.info(LOG_LABEL, "--------onStart2");
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
Button button2 = (Button) findComponentById(ResourceTable.Id_button2);
button2.setClickedListener(component -> {
//构造包含DeviceId、BundleName与AbilityName的Operation对象来设置目标Service信息
Intent intent1 = new Intent();
ElementName elementName = new ElementName("","com.example.myapplication","ServiceAbility1");
intent1.setElement(elementName);
stopAbility(intent1);
});
}
}
停止远程设备Service
/**
* 停止本地设备的Service
* @param intent
*/
@Override
public void onStart(Intent intent) {
HiLog.info(LOG_LABEL, "--------onStart2");
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//获取设备列表
List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
if(deviceList.isEmpty()){
return ;
}
int deviceNum = deviceList.size();
List<String> deviceIds = new ArrayList<>(deviceNum);
List<String> deviceNames = new ArrayList<>(deviceNum);
deviceList.forEach((device)->{
deviceIds.add(device.getDeviceId());
deviceNames.add(device.getDeviceName());
});
//使用deviceIds的第一个元素,做为启动远程设备的目标id
String devcieIdStr = deviceIds.get(0);
Button button2 = (Button) findComponentById(ResourceTable.Id_button2);
button2.setClickedListener(component -> {
Intent intent1 = new Intent();
ElementName elementName = new ElementName(devcieIdStr,"com.example.myapplication","ServiceAbility1");
intent1.setElement(elementName);
intent1.setFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE); // 设置支持分布式调度系统多设备启动的标识
stopAbility(intent1);
});
}
5.连接Service
如果Service需要与Page Ability或其他应用的Service Ability进行交互,则应创建用于连接的Connection。Service支持其他Ability通过connectAbility()方法与其进行连接。
在使用connectAbility()处理回调时,需要传入目标Service的Intent与IAbilityConnection的实例。
IAbilityConnection提供了两个方法供开发者实现:
onAbilityConnectDone()用来处理连接的回调
onAbilityDisconnectDone()用来处理断开连接的回调。
链接与启动的不同在于链接Service后,可以进行通信,也就是需要链接的Service执行任务后返回数据,此时,就要用链接而不能是启动。
客户端可通过调用disconnectAbility()断开连接。
// 与远程PA断开连接
private ClickedListener mDisconnectRemotePAListener = new ClickedListener() {
@Override
public void onClick(Component arg0) {
disconnectAbility(conn);
}
使用代理跨设备调度
在onAbilityConnectDone()中获取管理链接的代理,进一步为了使用该代理跨设备调度PA,开发者需要在本地及对端分别实现对外接口一致的代理。
发起连接端
package com.example.myapplication.connections;
import ohos.rpc.*;
public class StartRemoteProxy implements IRemoteBroker {
//发起端与接受端之间的通信代码,有效的任意值
private static final int MSGCODE = IRemoteObject.MIN_TRANSACTION_ID;
//通信成功的code值: 0
private static final int OK = 0;
//获取远程代理对象的持有者
private final IRemoteObject remote;
/**
* 初始远端代理对象,使用onAbilityDisconnectDone接口方法返回来获取
*
* @param remote
*/
public StartRemoteProxy(IRemoteObject remote) {
this.remote = remote;
}
/**
* 获取远程代理对象
*
* @return
*/
@Override
public IRemoteObject asObject() {
return remote;
}
/**
* Servcie Ability具有的test功能
*
* @param text
* @return
*/
public String test(String text) {
//传出的数据
MessageParcel data = MessageParcel.obtain(); //返回一个空的MessageParcel对象
data.writeString(text);
//远端返回的响应数据
MessageParcel reply = MessageParcel.obtain();
//制定信息传输的模式的option 同步 or 异步
MessageOption option = new MessageOption(MessageOption.TF_SYNC);
String result = null;
try {
//最核心方法,实现调用Servcie Ability的功能
remote.sendRequest(MSGCODE, data, reply, option);
//通信结束,响应结果存放在reply容器中
//判断通信状态
int ec = reply.readInt();
if (ec != OK) {
throw new RemoteException();
}
result = reply.readString();
} catch (RemoteException e) {
e.printStackTrace();
}
return result;
}
}
接受端
package com.example.myapplication.connections;
import ohos.rpc.*;
public class AcceptRemoteProxy extends RemoteObject implements IRemoteBroker {
//发起端与接受端之间的通信代码,有效的任意值
private static final int MSGCODE = IRemoteObject.MIN_TRANSACTION_ID;
//通信成功的code值 0
private static final int OK = 0;
//通信失败的Code值
private static final int ERROR = -1;
public AcceptRemoteProxy() {
super("this is acceptRemoteProxy");
}
@Override
public IRemoteObject asObject() {
return this;
}
/**
* 接受端接受发送端的请求数据,并处理这些数据,返回返回响应
*
* @param code 接受端与发送端间的通信code
* @param data 发送端发送的数据
* @param reply 接受端响应的数据
* @param option 数据传输的模式
* @return
* @throws RemoteException
*/
@Override
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
//发起端的通信code需与接受端通信code值一致
if (code != MSGCODE) {
//通信失败
reply.writeInt(ERROR);
return false;
}
//取发起端传递的参数
String readString = data.readString();
//设置返回发起端的响应数据
reply.writeInt(OK);
reply.writeString(readString);
return true;
}
}
创建Service Ability
一个PA ServiceAbility1 ,实例化一个代理返回给发起端
public class ServiceAbility1 extends Ability {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0xD001101, "ServiceAbility1");
//实例化客户端,返回给发送方可调用的代理
private AcceptRemoteProxy remote = new AcceptRemoteProxy();
/**
* 当该PA接收到连接请求时,将该客户端转化为代理返回给发起端
* @param intent
* @return
*/
@Override
public IRemoteObject onConnect(Intent intent) {
return remote;
}
@Override
public void onStart(Intent intent) {
HiLog.error(LABEL_LOG, "--------ServiceAbility1::onStart");
super.onStart(intent);
}
/**
* 每次调用ServiceAbility1都会执行该方法
*
* @param intent 数据载体
* @param restart 启动状态 true:销毁后启动,false:正常启动
* @param startId 启动的计数器
*/
@Override
public void onCommand(Intent intent, boolean restart, int startId) {
HiLog.info(LABEL_LOG, "--------ServiceAbility1::onCommand");
HiLog.info(LABEL_LOG, "--------ServiceAbility1::1数据载体:" + intent.getOperation().getAbilityName());
HiLog.info(LABEL_LOG, "--------ServiceAbility1::启动状态:" + restart);
HiLog.info(LABEL_LOG, "--------ServiceAbility1::启动的计数器:" + startId);
}
@Override
public void onDisconnect(Intent intent) {
HiLog.info(LABEL_LOG, "--------连接Service断开::onDisconnect");
}
}
创建Page Ability
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00002, "MainAbilitySlice");
private StartRemoteProxy startRemoteProxy = null;
// 创建连接回调实例
private IAbilityConnection conn = new IAbilityConnection() {
//连接到Service的回调
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
// Client侧(StartRemoteProxy)需要定义与Service侧(AcceptRemoteProxy)相同的IRemoteObject实现类。
// 开发者获取服务端传过来IRemoteObject对象,并从中解析出服务端传过来的信息。
startRemoteProxy = new StartRemoteProxy(iRemoteObject);
HiLog.info(LOG_LABEL, "--------连接Service" + startRemoteProxy.toString());
}
// 意外情况导致断开连接的回调
@Override
public void onAbilityDisconnectDone(ElementName elementName, int i) {
HiLog.info(LOG_LABEL, "--------意外情况导致断开连接");
}
};
@Override
public void onStart(Intent intent) {
HiLog.info(LOG_LABEL, "--------onStart2");
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//链接service
Button button1 = (Button) findComponentById(ResourceTable.Id_button1);
button1.setClickedListener(component -> {
Intent connectPAIntent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.myapplication")
.withAbilityName("com.example.myapplication.ServiceAbility1")
.build();
connectPAIntent.setOperation(operation);
connectAbility(connectPAIntent, conn);
});
//连接后进行通信
Button button2 = (Button) findComponentById(ResourceTable.Id_button2);
button2.setClickedListener(component -> {
if (startRemoteProxy != null) {
String rs = startRemoteProxy.test("hello world!");
HiLog.info(LOG_LABEL, "-------接受端响应数据:" + rs);
}
});
//断开链接service
Button button3 = (Button) findComponentById(ResourceTable.Id_button3);
button3.setClickedListener(component -> {
disconnectAbility(conn);
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:orientation="vertical">
<Button
ohos:id="$+id:button1"
ohos:width="match_content"
ohos:height="match_content"
ohos:background_element="$graphic:background_button"
ohos:text="连接Service"
ohos:layout_alignment="horizontal_center"
ohos:text_size="100"/>
<Button
ohos:id="$+id:button2"
ohos:width="match_content"
ohos:top_margin="100px"
ohos:height="match_content"
ohos:background_element="$graphic:background_button"
ohos:text="连接后通信"
ohos:layout_alignment="horizontal_center"
ohos:text_size="100"/>
<Button
ohos:id="$+id:button3"
ohos:width="match_content"
ohos:top_margin="100px"
ohos:height="match_content"
ohos:background_element="$graphic:background_button"
ohos:text="断开Service"
ohos:layout_alignment="horizontal_center"
ohos:text_size="100"/>
</DirectionalLayout>
本地设备连接Service
远程设备连接Service
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00002, "MainAbilitySlice");
private StartRemoteProxy startRemoteProxy = null;
// 创建连接回调实例
private IAbilityConnection conn = new IAbilityConnection() {
//连接到Service的回调
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
// Client侧(StartRemoteProxy)需要定义与Service侧(AcceptRemoteProxy)相同的IRemoteObject实现类。
// 开发者获取服务端传过来IRemoteObject对象,并从中解析出服务端传过来的信息。
startRemoteProxy = new StartRemoteProxy(iRemoteObject);
HiLog.info(LOG_LABEL, "--------连接Service" + startRemoteProxy.toString());
}
// 意外情况导致断开连接的回调
@Override
public void onAbilityDisconnectDone(ElementName elementName, int i) {
HiLog.info(LOG_LABEL, "--------意外情况导致断开连接");
}
};
@Override
public void onStart(Intent intent) {
HiLog.info(LOG_LABEL, "--------onStart2");
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//获取设备列表
List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
if(deviceList.isEmpty()){
return ;
}
int deviceNum = deviceList.size();
List<String> deviceIds = new ArrayList<>(deviceNum);
List<String> deviceNames = new ArrayList<>(deviceNum);
deviceList.forEach((device)->{
deviceIds.add(device.getDeviceId());
deviceNames.add(device.getDeviceName());
});
//使用deviceIds的第一个元素,做为启动远程设备的目标id
String devcieIdStr = deviceIds.get(0);
//链接service
Button button1 = (Button) findComponentById(ResourceTable.Id_button1);
button1.setClickedListener(component -> {
if(devcieIdStr!=null){
Intent connectPAIntent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.myapplication")
.withAbilityName("com.example.myapplication.ServiceAbility1")
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
connectPAIntent.setOperation(operation);
connectAbility(connectPAIntent, conn);
}
});
//连接后进行通信
Button button2 = (Button) findComponentById(ResourceTable.Id_button2);
button2.setClickedListener(component -> {
if (startRemoteProxy != null) {
String rs = startRemoteProxy.test("hello world!");
HiLog.info(LOG_LABEL, "-------接受端响应数据:" + rs);
}
});
//断开链接service
Button button3 = (Button) findComponentById(ResourceTable.Id_button3);
button3.setClickedListener(component -> {
disconnectAbility(conn);
});
}
}
6.生命周期
Ability为启动Service提供了以下生命周期方法,可以重写这些方法来添加自己的处理。Service将在其他Ability调用startAbility()时创建,然后保持运行。其他Ability通过调用stopAbility()来停止Service,Service停止后,系统会将其销毁。
根据调用方法的不同,其生命周期有以下两种路径:
启动Service
该Service在其他Ability调用startAbility()时创建,然后保持运行。其他Ability通过调用stopAbility()来停止Service,Service停止后,系统会将其销毁。
连接Service
该Service在其他Ability调用connectAbility()时创建,客户端可通过调用disconnectAbility()断开连接。多个客户端可以绑定到相同Service,而且当所有绑定全部取消后,系统即会销毁该Service。
该方法在创建Service的时候调用,用于Service的初始化。在Service的整个生命周期只会调用一次,调用时传入的Intent应为空。
onCommand()
在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用,用户可以在该方法中做一些调用统计、初始化类的操作。
onConnect()
在Ability和Service连接时调用,该方法返回IRemoteObject对象,用户可以在该回调函数中生成对应Service的IPC通信通道,以便Ability与Service交互。Ability可以多次连接同一个Service,系统会缓存该Service的IPC通信对象,只有第一个客户端连接Service时,系统才会调用Service的onConnect方法来生成IRemoteObject对象,而后系统会将同一个RemoteObject对象传递至其他连接同一个Service的所有客户端,而无需再次调用onConnect方法。
onDisconnect()
在Ability与绑定的Service断开连接时调用。
onStop()
在Service销毁时调用。Service应通过实现此方法来清理任何资源,如关闭线程、注册的侦听器等。
7.生命周期测试
启动/停止Service的生命周期
第一次启动本地设备的Service
01-10 11:45:56.905 7290-7290/com.example.myapplication E 01101/ServiceAbility1: --------ServiceAbility1::onStart
01-10 11:45:56.906 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::onCommand
01-10 11:45:56.906 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::1数据载体:com.example.myapplication.ServiceAbility1
01-10 11:45:56.906 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::启动状态:false
01-10 11:45:56.906 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::启动的计数器:1
第二次启动本地设备的Service
01-10 11:48:18.613 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::onCommand
01-10 11:48:18.613 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::1数据载体:com.example.myapplication.ServiceAbility1
01-10 11:48:18.613 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::启动状态:false
01-10 11:48:18.613 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::启动的计数器:2
当点击停止本地设备的Service时
01-10 11:49:31.327 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::onBackground
01-10 11:49:31.327 7290-7290/com.example.myapplication I 01101/ServiceAbility1: --------ServiceAbility1::onStop
启动/停止Service的生命周期
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/137078.html