自學(xué)HarmonyOS應(yīng)用開發(fā)(57)- 與Service進行交互

生成一個Service之后,就需要構(gòu)建一個Connection對象并通過它實現(xiàn)PageAbility和ServiceAbility之間的交互。
構(gòu)建自己的Connection類
StopWatchServiceConnection類的主要功能有兩個:一是接受連接成功通知并獲取服務(wù)端傳過來的用于通信的IRemoteObject對象,這是onAbilityConnectDone方法的主要工作;二是接收連接成功切斷時的通知。
public class StopWatchServiceConnection implements IAbilityConnection {static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00211, "StopWatchServiceConnection");public static final int EVENT_CONNECT_DONE = 0x1000001;public static final int EVENT_DISCONNECT_DONE = 0x1000002;/*** handle message from service to ability slice*/private static EventHandler handler = new EventHandler(EventRunner.current()) {protected void processEvent(InnerEvent event) {switch(event.eventId){case EVENT_CONNECT_DONE:break;case EVENT_DISCONNECT_DONE:break;}}};public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {HiLog.info(LOG_LABEL, "%{public}s", "onAbilityConnectDone resultCode : " + resultCode);InnerEvent innerEvent = InnerEvent.get(EVENT_CONNECT_DONE, resultCode, new StopWatchAgentProxy(iRemoteObject));handler.sendEvent(innerEvent);}public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {HiLog.info(LOG_LABEL, "%{public}s", "onAbilityDisconnectDone resultCode : " + resultCode);InnerEvent innerEvent = InnerEvent.get(EVENT_DISCONNECT_DONE, resultCode);handler.sendEvent(innerEvent);}}
需要說明的是:由于onAbilityConnectDone和onAbilityDisconnectDone不是UI線程上下文中被調(diào)用,因此必須通過一個EventHandler進行上下文切換之后才能安全地在UI線程中使用。
使用Connection類
StopWatchServiceConnection構(gòu)建完成之后,就可以使用它在PageAbility和ServiceAbility之間建立溝通渠道。
private void connectService() {HiLog.info(LOG_LABEL, "MainAbilitySlice.connectService!");Intent intent = getLocalServiceIntent(LOCAL_BUNDLE, FOREGROUND_SERVICE);connection = new StopWatchServiceConnection();connectAbility(intent, connection);}private Intent getLocalServiceIntent(String bundleName, String serviceName) {Operation operation = new Intent.OperationBuilder().withDeviceId("").withBundleName(bundleName).withAbilityName(serviceName).build();Intent intent = new Intent();intent.setOperation(operation);return intent;}
代碼第4行用到了前面構(gòu)建的StopWatchServiceConnection類。
通過IRemoteObject調(diào)用Service Ability的功能
IRemoteObject作為HarmonyOS中的基礎(chǔ)類,只提供線程通信的基本功能,開發(fā)者還需要另外定義和實現(xiàn)業(yè)務(wù)領(lǐng)域的接口。
我們使用HarmonyOS IDL定義如下接口:
interface xwg.harmony.stopwatch.StopWatchAgent {/** Example of a service method that uses some parameters*/void setCurrentTab([in] int index);int getCurrentTab();boolean start();void stop();boolean isRunning();long getStartTime();long getTime();void resetTime();void recordTime();String[] getLapTimes();void registerLocationEvent();double[] getCurrentLocation();}
我們將這個文件加入到項目中,啟動編譯過程之后,DevEco Studio會自動生成三個用于線程通信的輔助類。
第一個是接口定義文件:
public interface StopWatchAgent extends IRemoteBroker {void setCurrentTab(/* [in] */ int index) throws RemoteException;int getCurrentTab() throws RemoteException;};
可以看到這個文件就是IDL文件的java語言實現(xiàn)。
第二個文件是用來將用戶請求進行封裝后調(diào)用IRemoteObject的功能進行線程或進程通信的StopWatchAgentProxy類。
public class StopWatchAgentProxy implements StopWatchAgent {public StopWatchAgentProxy(/* [in] */ IRemoteObject remote) {this.remote = remote;}public IRemoteObject asObject() {return remote;}public void setCurrentTab(/* [in] */ int index) throws RemoteException {MessageParcel data = MessageParcel.obtain();MessageParcel reply = MessageParcel.obtain();MessageOption option = new MessageOption(MessageOption.TF_SYNC);data.writeInterfaceToken(DESCRIPTOR);data.writeInt(index);try {remote.sendRequest(COMMAND_SET_CURRENT_TAB, data, reply, option);reply.readException();} finally {data.reclaim();reply.reclaim();}}public int getCurrentTab() throws RemoteException {MessageParcel data = MessageParcel.obtain();MessageParcel reply = MessageParcel.obtain();MessageOption option = new MessageOption(MessageOption.TF_SYNC);data.writeInterfaceToken(DESCRIPTOR);try {remote.sendRequest(COMMAND_GET_CURRENT_TAB, data, reply, option);reply.readException();int result = reply.readInt();return result;} finally {data.reclaim();reply.reclaim();}}};
代碼比較長,但每個接口的套路都一樣。有了使用StopWatchAgentProxy,PageAbility就可以直接調(diào)用ServiceAbility的功能,而不需要關(guān)心這些功能是在其他線程還是其他設(shè)備。
最后是一個用于幫助ServiceAbility實現(xiàn)接口的StopWatchAgengStub類:
public abstract class StopWatchAgentStub extends RemoteObject implements StopWatchAgent {...public StopWatchAgentStub(/* [in] */ String descriptor) {super(descriptor);}public IRemoteObject asObject() {return this;}public static StopWatchAgent asInterface(IRemoteObject object) {if (object == null) {return null;}StopWatchAgent result = null;IRemoteBroker broker = object.queryLocalInterface(DESCRIPTOR);if (broker != null) {if (broker instanceof StopWatchAgent) {result = (StopWatchAgent)broker;}} else {result = new StopWatchAgentProxy(object);}return result;}public boolean onRemoteRequest(/* [in] */ int code,/* [in] */ MessageParcel data,/* [out] */ MessageParcel reply,/* [in] */ MessageOption option) throws RemoteException {String token = data.readInterfaceToken();if (!DESCRIPTOR.equals(token)) {return false;}switch (code) {case COMMAND_SET_CURRENT_TAB: {int index = data.readInt();setCurrentTab(index);reply.writeNoException();return true;}case COMMAND_GET_CURRENT_TAB: {int result;result = getCurrentTab();reply.writeNoException();reply.writeInt(result);return true;}default:return super.onRemoteRequest(code, data, reply, option);}}};
有了StopWatchAgengStub類,ServiceAbility類可以直接實現(xiàn)所需功能而無需關(guān)心線程/進程通信的各種細節(jié):
StopWatchAgentStub remoteAgentStub = new StopWatchAgentStub(DESCRIPTOR) {public void setCurrentTab(int index) throws RemoteException {current_tab = index;}public int getCurrentTab() throws RemoteException {return current_tab;}...};
參考代碼
完整代碼可以從以下鏈接下載:
https://github.com/xueweiguo/Harmony/tree/master/StopWatch
參考資料:
接口描述語言簡介
https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835
作者著作介紹
《實戰(zhàn)Python設(shè)計模式》是作者去年3月份出版的技術(shù)書籍,該書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過可執(zhí)行的示例對23 個設(shè)計模式逐個進行說明。這樣一方面可以使讀者了解真實的軟件開發(fā)工作中每個設(shè)計模式的運用場景和想要解決的問題;另一方面通過對這些問題的解決過程進行說明,讓讀者明白在編寫代碼時如何判斷使用設(shè)計模式的利弊,并合理運用設(shè)計模式。

對設(shè)計模式感興趣而且希望隨學(xué)隨用的讀者通過本書可以快速跨越從理解到運用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計和開發(fā)的參考;使用Python 語言進行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺得本文有幫助?請分享給更多人。
關(guān)注微信公眾號【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>
