【木棉花】:Service核心技术精要直播之学习笔记(下) 原创 精华
前言
这篇文章是我观看张荣超老师8月12日Service核心技术精要的直播后的学习笔记,温故而知新,跟着敲代码,跟着学知识,冲冲冲O(∩_∩)O
概述
这是直播的主要内容,本文是对连接和断开连接应用内的Service和跨设备连接和断开连接应用内的Service两个Demo做点笔记记录
正文
一、知识要点
1、连接Service:如果Service需要与Page Ability或其他应用的Service Ability进行交互,则须创建用于连接的Connection。Service支持其他Ability通过connectAbility()方法与其进行连接。
在使用connectAbility() 处理回调时,需要传入目标Service的Intent与IAbilityConnection的实例。IAbilityConnection提供了两个方法供开发者实现:onAbilityConnectDone() 是用来处理连接Service成功的回调,onAbilityDisconnectDone() 是用来处理Service异常死亡的回调。同时,Service侧也需要在onConnect() 时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象,HarmonyOS提供了IRemoteObject的默认实现,用户可以通过继承LocalRemoteObject来创建自定义的实现类
二、连接和断开连接应用内的Service
1.界面布局
/ability_main.xml/
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
>
<Text
ohos:id="$+id:text_main"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="这是MainAbility"
ohos:text_size="40vp"
/>
<Button
ohos:id="$+id:btn_connect"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="连接APP内的Service"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_call"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="调用Service的方法"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_disconnect"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="断开连接Service"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_to_second"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="跳转到SecondAbility"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
</DirectionalLayout>
/ability_second.xml/
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
>
<Text
ohos:id="$+id:text_sec"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="这是SecondAbility"
ohos:text_size="40vp"
/>
<Button
ohos:id="$+id:btn_sec_connect"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="连接APP内的Service"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_sec_call"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="调用Service的方法"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_sec_disconnect"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="断开连接Service"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
<Button
ohos:id="$+id:btn_to_main"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="跳转到MainAbility"
ohos:text_color="#ffffff"
ohos:background_element="$graphic:background_button"
ohos:left_margin="30vp"
ohos:right_margin="30vp"
ohos:top_margin="30vp"
ohos:bottom_margin="30vp"
ohos:top_padding="10vp"
ohos:bottom_padding="10vp"
ohos:auto_font_size="true"
/>
</DirectionalLayout>
2.ServiceAbility
设置一下打印日志的内容,定义一个内部类,定义一个方法plus作为Service调用的方法;在连接Service调用onConnect时返回这个内部类的一个实例对象
public class ServiceAbility extends Ability {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
public static class MyLocalRemoteObject extends LocalRemoteObject{
public MyLocalRemoteObject() {
super();
}
public int plus(int num1, int num2){
return num1 + num2;
}
}
@Override
public void onStart(Intent intent) {
HiLog.info(LABEL_LOG, "onStart()被调用了");
super.onStart(intent);
}
@Override
public IRemoteObject onConnect(Intent intent) {
HiLog.info(LABEL_LOG, "onConnect()被调用了");
return new MyLocalRemoteObject();
}
@Override
public void onDisconnect(Intent intent) {
HiLog.info(LABEL_LOG, "onDisconnect()被调用了");
}
@Override
public void onBackground() {
super.onBackground();
HiLog.info(LABEL_LOG, "onBackground()被调用了");
}
@Override
public void onStop() {
super.onStop();
HiLog.info(LABEL_LOG, "onStop()被调用了");
}
@Override
public void onCommand(Intent intent, boolean restart, int startId) {
HiLog.info(LABEL_LOG, "onCommand()被调用了");
}
}
3.AbilitySlice
onAbilityConnectDone中的形参为iRemoteObject,要将其转化为它实际的类型,系统为这个形参传入的实参是Service中的onConnect返回的实例对象。
当本应用调用方法connectAbility的时候,就会根据指定的intent对象和AbilityConnection去连接Service,如果Service没有被其他Ability连接,那么系统就会先创建Service,并且回调onStart来初始化Service,然后再回调onConnect连接Service;如果已经连接到其他Ability,那么系统会直接回调onAbilityConnectDone。只有当所有Ability都与Service断开连接了,系统才与Service断开连接。
创建一个SecondAbility,如果跳转页面不成功可以去看看配置文件config.json是否配置了SecondAbility的相关信息
/MainAbilitySlice/
public class MainAbilitySlice extends AbilitySlice {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
private ServiceAbility.MyLocalRemoteObject myLocalRemoteObject;
private final IAbilityConnection abilityConnection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
HiLog.info(LABEL_LOG,"onAbilityConnectDone()被调用了");
myLocalRemoteObject = (ServiceAbility.MyLocalRemoteObject)iRemoteObject;
}
@Override
public void onAbilityDisconnectDone(ElementName elementName, int i) {
HiLog.info(LABEL_LOG,"onAbilityDisconnectDone()被调用了");
}
};
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
setListenerForBtnConnect();
setListenerForBtnCall();
setListenerForBtnDisconnect();
setListenerForBtnToSecond();
}
private void setListenerForBtnConnect(){
Intent intent = new Intent();
Operation serviceOperation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(getBundleName())
.withAbilityName(ServiceAbility.class.getName())
.build();
intent.setOperation(serviceOperation);
Component btnConnect = (Button)findComponentById(ResourceTable.Id_btn_connect);
btnConnect.setClickedListener(component -> {
connectAbility(intent,abilityConnection);
});
}
private void setListenerForBtnCall(){
Button btnCall = (Button)findComponentById(ResourceTable.Id_btn_call);
btnCall.setClickedListener(component -> {
if(myLocalRemoteObject != null){
int result = myLocalRemoteObject.plus(2,3);
HiLog.info(LABEL_LOG,"plus(2,3)的返回值:"+result);
}
});
}
private void setListenerForBtnDisconnect(){
Button btnDisconnect = (Button)findComponentById(ResourceTable.Id_btn_disconnect);
btnDisconnect.setClickedListener(component -> {
disconnectAbility(abilityConnection);
});
}
private void setListenerForBtnToSecond(){
Intent intent = new Intent();
Operation serviceOperation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(getBundleName())
.withAbilityName(SecondAbility.class.getName())
.build();
intent.setOperation(serviceOperation);
Button btnToSecond = (Button)findComponentById(ResourceTable.Id_btn_to_second);
btnToSecond.setClickedListener(component -> {
HiLog.info(LABEL_LOG,"ToSecond()被调用了");
startAbility(intent);
});
}
}
/SecondAbilitySlice/
public class SecondAbilitySlice extends AbilitySlice {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
private ServiceAbility.MyLocalRemoteObject myLocalRemoteObject;
private final IAbilityConnection abilityConnection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
HiLog.info(LABEL_LOG,"onAbilityConnectDone()被调用了");
myLocalRemoteObject = (ServiceAbility.MyLocalRemoteObject)iRemoteObject;
}
@Override
public void onAbilityDisconnectDone(ElementName elementName, int i) {
HiLog.info(LABEL_LOG,"onAbilityDisconnectDone()被调用了");
}
};
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_second);
setListenerForBtnConnect();
setListenerForBtnCall();
setListenerForBtnDisconnect();
setListenerForBtnToMain();
}
private void setListenerForBtnConnect(){
Intent intent = new Intent();
Operation serviceOperation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(getBundleName())
.withAbilityName(ServiceAbility.class.getName())
.build();
intent.setOperation(serviceOperation);
Component btnConnect = (Button)findComponentById(ResourceTable.Id_btn_sec_connect);
btnConnect.setClickedListener(component -> {
connectAbility(intent,abilityConnection);
});
}
private void setListenerForBtnCall(){
Button btnCall = (Button)findComponentById(ResourceTable.Id_btn_sec_call);
btnCall.setClickedListener(component -> {
if(myLocalRemoteObject != null){
int result = myLocalRemoteObject.plus(5,6);
HiLog.info(LABEL_LOG,"plus(5,6)的返回值:"+result);
}
});
}
private void setListenerForBtnDisconnect(){
Button btnDisconnect = (Button)findComponentById(ResourceTable.Id_btn_sec_disconnect);
btnDisconnect.setClickedListener(component -> {
disconnectAbility(abilityConnection);
});
}
private void setListenerForBtnToMain(){
Button btnToMain = (Button)findComponentById(ResourceTable.Id_btn_to_main);
btnToMain.setClickedListener(component -> {
terminateAbility();
});
}
}
打印的日志如下
三、跨设备连接和断开连接应用内的Service
代码内容跟跨设备启动和停止Service差不多,要配置相关权限,发送弹窗形式请求用户授权,再定义一个工具类去获取所有设备的Id列表… …
要点:1.本地设备连接和断开连接应用内的Service中的ServiceAbility的内部类是继承LocalRemoteObject,而跨设备的是继承RemoteAbilityStub。
2.RemoteAbilityStub这个类来自idl,idl:当跨进程进行通信的时候,它可以用于定义客户端和服务端两者共同认可的接口,创建idl文件,定义好接口后,打开Gradle,找到对应模块下的下图的位置compileDebugIdl双击,系统会自动生成三个文件,一个是接口文件,一个是客户端的代理类,一个是服务端的装类.
结语
以上就是我这次的小分享啦❀❀!!2022,学习路上继续前进!