HarmonyOS 分布式新聞分享
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
1. 介紹
HarmonyOS支持應(yīng)用以Ability為單位進(jìn)行部署,Ability可以分為FA(Feature Ability)和PA(Particle Ability)兩種類型,本篇Codelab將會(huì)使用到Page Ability以及Service Ability來(lái)進(jìn)行開發(fā),其中Page Ability是FA唯一支持的模板,用于提供與用戶交互的能力,Service Ability是PA(Particle Ability)的一種,用于提供后臺(tái)運(yùn)行任務(wù)的能力。除此之外,您還將使用到HarmonyOS中的常用控件如:ListContainer,Image等,以及跨設(shè)備拉起FA的能力來(lái)共同實(shí)現(xiàn)一個(gè)基于分布式的HarmonyOS簡(jiǎn)易新聞客戶端。
最終效果預(yù)覽
我們最終會(huì)構(gòu)建一個(gè)簡(jiǎn)易的HarmonyOS新聞客戶端。應(yīng)用包含兩級(jí)頁(yè)面,分別是主頁(yè)面和詳情頁(yè)面,兩個(gè)頁(yè)面都展示了豐富的HarmonyOS組件,其中詳情頁(yè)的實(shí)現(xiàn)邏輯中還展示了如何通過(guò)調(diào)用相應(yīng)接口,實(shí)現(xiàn)跨設(shè)備拉起FA。本篇Codelab我們將會(huì)一起完成這個(gè)客戶端,其中包括:
1.頂部ListContainer以及新聞列表ListContainer
2.每條新聞的文本框以及圖像
3.布局及頁(yè)面跳轉(zhuǎn)
4.設(shè)備發(fā)現(xiàn)以及跨設(shè)備拉起FA

2. 搭建HarmonyOS環(huán)境
安裝DevEco Studio,詳情請(qǐng)參考DevEco Studio下載。
設(shè)置DevEco Studio開發(fā)環(huán)境,DevEco Studio開發(fā)環(huán)境需要依賴于網(wǎng)絡(luò)環(huán)境,需要連接上網(wǎng)絡(luò)才能確保工具的正常使用,可以根據(jù)如下兩種情況來(lái)配置開發(fā)環(huán)境:
如果可以直接訪問(wèn)Internet,只需進(jìn)行下載HarmonyOS SDK操作。
如果網(wǎng)絡(luò)不能直接訪問(wèn)Internet,需要通過(guò)代理服務(wù)器才可以訪問(wèn),請(qǐng)參考配置開發(fā)環(huán)境。
說(shuō)明:
如需要在手機(jī)中運(yùn)行程序,則需要提前申請(qǐng)證書,如使用模擬器可忽略。
你可以通過(guò)如下設(shè)備完成Codelab:
開啟開發(fā)者模式的HarmonyOS真機(jī)
DevEco Studio中的手機(jī)模擬器(模擬器暫不支持分布式調(diào)試)
3. 代碼結(jié)構(gòu)解讀
本篇Codelab只對(duì)核心代碼進(jìn)行講解,對(duì)于完整代碼,我們會(huì)在參考中提供下載方式,接下來(lái)我們會(huì)用一小節(jié)來(lái)講解整個(gè)工程的代碼結(jié)構(gòu):
- INewsDemoIDL.idl:存放在entry\src\main\idl\com\huawei\newsdemo目錄下,接口中定義了tranShare方法用來(lái)實(shí)現(xiàn)不同設(shè)備之間的通信。
- bean:NewsInfo封裝了新聞信息,NewsType封裝了新聞?lì)愋汀?/li>
- provider:DevicesListProvider,NewsListProvider,NewsTypeProvider,分別為設(shè)備列表,主頁(yè)新聞列表以及新聞?lì)愋偷膒rovider,主要作用為高效傳遞和使用相關(guān)數(shù)據(jù)。
- slice:NewsListAbilitySlice,NewsDetailAbilitySlice分別為進(jìn)入應(yīng)用的主頁(yè)面和詳情頁(yè)面,同時(shí)里面也展現(xiàn)了我們大部分的邏輯實(shí)現(xiàn)。
- utils:存放所有封裝好的公共方法,如CommonUtils,DialogUtils等。
- NewsAbility:動(dòng)態(tài)權(quán)限的申請(qǐng)以及頁(yè)面路由信息處理。
- SharedService:供遠(yuǎn)端連接的Service Ability。
- manager:該目錄下的文件為INewsDemoIDL.idl在編譯時(shí)自行生成,初始生成位置為entry\build\generated\source\idl\com\huawei\newsdemo。
- resources:存放工程使用到的資源文件,其中resources\base\layout下存放xml布局文件;resources\base\media下存放圖片資源;resources\rawfile下存放應(yīng)用使用的新聞數(shù)據(jù)json文件。
- config.json:配置文件

4. 添加主頁(yè)頂部新聞?lì)愋?/h2>
首先為我們的應(yīng)用添加頂部新聞?lì)愋停糜谇袚Q不同類別的新聞,我們會(huì)使用到ListContainer控件,有關(guān)ListContainer的更多知識(shí),可以參考HarmonyOS JAVA通用組件。
首先需要在布局文件中對(duì)控件進(jìn)行聲明,在resources\base\layout\news_list_layout.xml布局文件中有如下代碼:
- <ListContainer
- ohos:id="$+id:selector_list"
- ohos:width="match_parent"
- ohos:height="40vp"
- ohos:orientation="horizontal"
- />
此外我們還定義了selectorListContainer變量進(jìn)行關(guān)聯(lián),在NewsListAbilitySlice.java的initView()方法中有如下代碼:
- selectorListContainer = (ListContainer) findComponentById(ResourceTable.Id_selector_list);
添加監(jiān)聽
在切換不同類別新聞的時(shí)候,下面展示的新聞列表項(xiàng)會(huì)跟隨切換,所以我們需要為這個(gè)ListContainer設(shè)置一個(gè)監(jiān)聽,在NewsListAbilitySlice.java的initListener()方法中添加:
- selectorListContainer.setItemClickedListener(
- (listContainer, component, position, id) -> {
- // 設(shè)置選中后的放大效果
- setCategorizationFocus(false);
- selectText = (Text) component.findComponentById(ResourceTable.Id_news_type_text);
- setCategorizationFocus(true);
- newsDataList.clear();
- for (NewsInfo mTotalNewsData : totalNewsDataList) {
- if (selectText.getText().equals(mTotalNewsData.getType()) || id == 0) {
- newsDataList.add(mTotalNewsData);
- }
- }
- updateListView();
- });
聲明NewsTypeProvider
為了方便我們的應(yīng)用更加高效和便捷的使用數(shù)據(jù),我們將應(yīng)用中用到的新聞數(shù)據(jù)事先預(yù)置在resources/rawfile目錄下的兩個(gè)json文件中,此外我們還聲明了一些Provider,便于數(shù)據(jù)的獲取和傳遞,其中獲取新聞?lì)悇e的NewsTypeProvider如下:
- @Override
- public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
- ViewHolder viewHolder;
- Component temp = component;
- if (temp == null) {
- temp = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_news_type_layout, null, false);
- // 將所有子組件通過(guò)ViewHolder綁定到列表項(xiàng)實(shí)例
- viewHolder = new ViewHolder();
- viewHolder.title = (Text) temp.findComponentById(ResourceTable.Id_news_type_text);
- component.setTag(viewHolder);
- } else {
- viewHolder = (ViewHolder) temp.getTag();
- }
- viewHolder.title.setText(mNewsTypeList.get(position).getName());
- return temp;
- }
我們定義了initData方法來(lái)解析json文件中的新聞數(shù)據(jù),并將這些數(shù)據(jù)傳遞給provider,在NewsListAbilitySlice.java的initData()添加如下代碼:
- private void initData() {
- Gson gson = new Gson();
- List<NewsType> newsTypeList =
- gson.fromJson(
- CommonUtils.getStringFromJsonPath(this, "entry/resources/rawfile/news_type_datas.json"),
- new TypeToken<List<NewsType>>(){ }.getType());
- newsTypeProvider = new NewsTypeProvider(newsTypeList, this);
- }
添加切換效果
在切換不同類別新聞的時(shí)候,增加了一個(gè)放大效果,在setCategorizationFocus()中添加如下代碼:
- private void setCategorizationFocus(boolean isFocus) {
- if (selectText == null) {
- return;
- }
- if (isFocus) {
- selectText.setTextColor(
- new Color(CommonUtils.getColor(NewsListAbilitySlice.this, ResourceTable.Color_news_type_text_on)));
- selectText.setScaleX(FOCUS_TEXT_SIZE);
- selectText.setScaleY(FRCUS_TEXT_SIZE);
- } else {
- selectText.setTextColor(
- new Color(CommonUtils.getColor(NewsListAbilitySlice.this, ResourceTable.Color_news_type_text_off)));
- selectText.setScaleX(UNFOCUS_TEXT_SIZE);
- selectText.setScaleY(UNFOCUS_TEXT_SIZE);
- }
所以在進(jìn)行類別切換的時(shí)候,將會(huì)得到如下效果:

5. 添加主頁(yè)新聞列表項(xiàng)
新聞列表項(xiàng)布局
主頁(yè)面的布局除了有上方的頂部欄,還由下方的新聞列表項(xiàng)構(gòu)成,整個(gè)新聞列表項(xiàng)是一個(gè)ListContainer,同樣我們先來(lái)看看在new_list_layout.xml中是如何定義的:
- <ListContainer
- ohos:id="$+id:news_container"
- ohos:width="match_parent"
- ohos:height="match_parent"/>
整個(gè)新聞列表項(xiàng)由多個(gè)新聞item構(gòu)成,每個(gè)item又由標(biāo)題和圖片構(gòu)成,每個(gè)item在item_news_layout.xml布局中是這樣定義的:
- <DirectionalLayout
- ohos:height="109.5vp"
- ohos:width="match_parent"
- ohos:orientation="horizontal"
- ohos:padding="10vp">
- <Text
- ohos:id="$+id:item_news_title"
- ohos:height="match_content"
- ohos:width="0vp"
- ohos:max_text_lines="3"
- ohos:multiple_lines="true"
- ohos:right_padding="20vp"
- ohos:text_size="18vp"
- ohos:weight="3"/>
- <Image
- ohos:id="$+id:item_news_image"
- ohos:height="match_parent"
- ohos:width="0vp"
- ohos:scale_mode="stretch"
- ohos:weight="2"/>
- </DirectionalLayout>
聲明NewsListProvider
和頂部新聞?lì)愋鸵粯樱總€(gè)新聞item中的title和image也是利用provider傳遞的,在NewsListProvider.java中有如下代碼:
- @Override
- public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
- ViewHolder viewHolder;
- Component temp = component;
- if (temp == null) {
- component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_news_layout, null, false);
- // 將所有子組件通過(guò)ViewHolder綁定到列表項(xiàng)實(shí)例
- viewHolder = new ViewHolder();
- viewHolder.title = (Text) temp.findComponentById(ResourceTable.Id_item_news_title);
- viewHolder.image = (Image) temp.findComponentById(ResourceTable.Id_item_news_image);
- temp.setTag(viewHolder);
- } else {
- viewHolder = (ViewHolder) temp.getTag();
- }
- viewHolder.title.setText(newsInfoList.get(i).getTitle());
- viewHolder.image.setPixelMap(CommonUtils.getPixelMapFromPath(context, newsInfoList.get(i).getImgUrl()));
- return temp;
- }
同樣,newsListProvider的數(shù)據(jù)也是在initData的時(shí)候進(jìn)行賦值的,所以需要在NewsListAbilitySlice的initData()中添加:
- totalNewsDataList =
- gson.fromJson(
- CommonUtils.getStringFromJsonPath(this, "entry/resources/rawfile/news_datas.json"),
- new TypeToken<List<NewsInfo>>(){ }.getType());
- newsDataList = new ArrayList<>();
- newsDataList.addAll(totalNewsDataList);
- newsListProvider = new NewsListProvider(newsDataList, this);
到此我們完成了數(shù)據(jù)的加載和解析,接下來(lái)是為item添加點(diǎn)擊事件。
添加監(jiān)聽
我們點(diǎn)擊某個(gè)具體新聞item的時(shí),應(yīng)用會(huì)跳轉(zhuǎn)到全局詳情頁(yè)面,這時(shí)要為新聞item添加一個(gè)監(jiān)聽,在NewsListAbilitySlice.java的initListener()中添加:
- newsListContainer.setItemClickedListener(
- (listContainer, component, position, id) -> {
- Intent intent = new Intent();
- Operation operation =
- new Intent.OperationBuilder()
- .withBundleName(getBundleName())
- .withAbilityName(NewsAbility.class.getName())
- .withAction("action.detail")
- .build();
- intent.setOperation(operation);
- intent.setParam(NewsDetailAbilitySlice.INTENT_TITLE, newsDataList.get(position).getTitle());
- intent.setParam(NewsDetailAbilitySlice.INTENT_READ, newsDataList.get(position).getReads());
- intent.setParam(NewsDetailAbilitySlice.INTENT_LIKE, newsDataList.get(position).getLikes());
- intent.setParam(NewsDetailAbilitySlice.INTENT_CONTENT, newsDataList.get(position).getContent());
- intent.setParam(NewsDetailAbilitySlice.INTENT_IMAGE, newsDataList.get(position).getImgUrl());
- startAbility(intent);
- });
這里的startAbility()是我們頁(yè)面跳轉(zhuǎn)的關(guān)鍵方法,參數(shù)intent里面存放了要跳轉(zhuǎn)的bundle name,ability name,詳情頁(yè)面的title,imgurl等重要參數(shù)。
6. 詳情頁(yè)頁(yè)面布局
新聞詳情頁(yè)的布局相比于新聞主頁(yè)稍微有些復(fù)雜,整體由DependentLayout布局嵌套DirectionalLayout布局、ScrollView和其他控件構(gòu)成,我們把整體頁(yè)面分為頂部,底部,和中部。并在resources\base\layout\new_detail_laylout.xml中實(shí)現(xiàn)詳情頁(yè)的布局。
頂部
頂部是由DirectionalLayout加上Text組件構(gòu)成,分別對(duì)應(yīng)了左側(cè)的圖標(biāo)和NewsDemo以及右側(cè)的reads和likes,實(shí)現(xiàn)效果及布局部分代碼如下:

- <DirectionalLayout
- ohos:width="match_parent"
- ohos:height="match_content"
- ohos:alignment="vertical_center"
- ohos:orientation="horizontal">
- <Text
- ohos:id="$+id:title_icon"
- ohos:width="match_content"
- ohos:height="match_content"
- ohos:weight="1"
- ohos:text="NewsDemo"
- ohos:text_size="20fp"/>
- <Text
- ohos:id="$+id:read_num"
- ohos:width="match_content"
- ohos:height="match_content"
- ohos:text_size="10fp"
- ohos:right_margin="10vp"/>
- <Text
- ohos:id="$+id:like_num"
- ohos:width="match_content"
- ohos:height="match_content"
- ohos:text_size="10fp"/>
- </DirectionalLayout>
中部
頁(yè)面的中間部分由新聞標(biāo)題Text,縮略圖Image,新聞內(nèi)容Text構(gòu)成,實(shí)現(xiàn)效果及布局部分代碼如下:

- <Text
- ohos:id="$+id:title_text"
- ohos:width="match_parent"
- ohos:height="match_content"
- ohos:text_size="18fp"
- ohos:max_text_lines="4"
- ohos:multiple_lines="true"
- ohos:text_color="#000000"
- ohos:top_margin="10vp"/>
- <Image
- ohos:id="$+id:image_content"
- ohos:width="match_parent"
- ohos:scale_mode="stretch"
- ohos:height="300vp"
- ohos:top_margin="10vp"/>
- <Text
- ohos:id="$+id:title_content"
- ohos:width="match_parent"
- ohos:height="match_content"
- ohos:multiple_lines="true"
- ohos:text_color="#708090"
- ohos:text_size="16vp"
- ohos:text_alignment="center_horizontal"
- ohos:top_margin="5vp"/>
底部
頁(yè)面的底部由DirectionalLayout加上TextField和Image控件構(gòu)成,對(duì)應(yīng)輸入評(píng)論和幾個(gè)按鈕,具體效果和部分布局代碼如下:

- <DirectionalLayout
- ohos:id="$+id:bottom_layout"
- ohos:align_parent_bottom="true"
- ohos:width="match_parent"
- ohos:height="50vp"
- ohos:orientation="horizontal"
- ohos:background_element="#ffffff"
- ohos:alignment="vertical_center"
- ohos:left_padding="20vp"
- ohos:right_padding="20vp"
- >
- <TextField
- ohos:id="$+id:text_file"
- ohos:width="160vp"
- ohos:height="30vp"
- ohos:left_padding="5vp"
- ohos:right_padding="10vp"
- ohos:text_alignment="vertical_center"
- ohos:text_size="15vp"
- ohos:hint="Enter a comment."
- ohos:background_element="$graphic:corner_bg_comment"/>
- <Image
- ohos:id="$+id:button1"
- ohos:width="20vp"
- ohos:height="20vp"
- ohos:image_src="$media:message_icon"
- ohos:scale_mode="stretch"
- ohos:left_margin="20vp"/>
- <Image
- ohos:id="$+id:button2"
- ohos:width="20vp"
- ohos:height="20vp"
- ohos:image_src="$media:collect_icon"
- ohos:scale_mode="stretch"
- ohos:left_margin="20vp"/>
- <Image
- ohos:id="$+id:button3"
- ohos:width="20vp"
- ohos:height="20vp"
- ohos:image_src="$media:like_icon"
- ohos:scale_mode="stretch"
- ohos:left_margin="20vp"/>
- <Image
- ohos:id="$+id:button4"
- ohos:width="20vp"
- ohos:height="20vp"
- ohos:image_src="$media:share_icon"
- ohos:scale_mode="stretch"
- ohos:left_margin="20vp"/>
- </DirectionalLayout>
7. 詳情頁(yè)數(shù)據(jù)初始化
接受來(lái)自NewsListAbilitySlice頁(yè)面的數(shù)據(jù)
我們?cè)谔砑有侣劻斜眄?xiàng)那一節(jié)中說(shuō)明了新聞頁(yè)面的title,imgurl等重要參數(shù)是如何存放的,現(xiàn)在我們一起看下在詳情頁(yè)是如何獲取的。在NewsDetailAbilitySlice.java的onStart()中有如下代碼:
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_news_detail_layout);
- reads = intent.getStringParam(INTENT_READ);
- likes = intent.getStringParam(INTENT_LIKE);
- title = intent.getStringParam(INTENT_TITLE);
- content = intent.getStringParam(INTENT_CONTENT);
- image = intent.getStringParam(INTENT_IMAGE);
- }
之前存放在intent中的參數(shù),現(xiàn)在在onStart()中逐一進(jìn)行取出。
布局和控件的初始化
除了需要聲明xml來(lái)實(shí)現(xiàn)布局以外,還需要在NewsDetailAbilitySlice.java的onStart()中添加initView()方法進(jìn)行初始化:
- private void initView() {
- parentLayout = (DependentLayout) findComponentById(ResourceTable.Id_parent_layout);
- commentFocus = (TextField) findComponentById(ResourceTable.Id_text_file);
- iconShared = (Image) findComponentById(ResourceTable.Id_button4);
- Text newsRead = (Text) findComponentById(ResourceTable.Id_read_num);
- Text newsLike = (Text) findComponentById(ResourceTable.Id_like_num);
- Text newsTitle = (Text) findComponentById(ResourceTable.Id_title_text);
- Text newsContent = (Text) findComponentById(ResourceTable.Id_title_content);
- Image newsImage = (Image) findComponentById(ResourceTable.Id_image_content);
- newsRead.setText("reads: " + reads);
- newsLike.setText("likes: " + likes);
- newsTitle.setText("Original title: " + title);
- newsContent.setText(content);
- newsImage.setPixelMap(CommonUtils.getPixelMapFromPath(this, image));
- }
添加監(jiān)聽
我們?cè)邳c(diǎn)擊頁(yè)面底部右下角的分享按鈕的時(shí)候,會(huì)進(jìn)行設(shè)備發(fā)現(xiàn)操作,并將發(fā)現(xiàn)的設(shè)備列表進(jìn)行展示,此處我們?cè)O(shè)置了兩個(gè)監(jiān)聽,在NewsDetailAbilitySlice.java的onStart()中添加initListener():
- private void initListener() {
- parentLayout.setTouchEventListener(
- (component, touchEvent) -> {
- if (commentFocus.hasFocus()) {
- commentFocus.clearFocus();
- }
- return true;
- });
- iconShared.setClickedListener(
- v -> {
- initDevices();
- showDeviceList();
- });
- }
parentLayout的監(jiān)聽事件用來(lái)監(jiān)聽觸控焦點(diǎn)是否在設(shè)備列表Dialog上,iconShared的監(jiān)聽事件用來(lái)監(jiān)聽分享按鈕被是否被點(diǎn)擊。

8. 設(shè)備發(fā)現(xiàn)
上一節(jié)我們了解到當(dāng)分享按鈕被點(diǎn)擊的時(shí)候會(huì)觸發(fā)監(jiān)聽,進(jìn)行設(shè)備發(fā)現(xiàn),那么觸發(fā)監(jiān)聽后,是如何進(jìn)行設(shè)備發(fā)現(xiàn)的?
在initListener()中有兩個(gè)有關(guān)設(shè)備發(fā)現(xiàn)的方法:initDevices()和showDeviceList()。initDevices()方法調(diào)用接口實(shí)現(xiàn)設(shè)備發(fā)現(xiàn),并將發(fā)現(xiàn)到的設(shè)備存儲(chǔ)到List中,需要如下代碼實(shí)現(xiàn):
- private void initDevices() {
- if (devices.size() > 0) {
- devices.clear();
- }
- List<DeviceInfo> deviceInfos =
- DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
- devices.addAll(deviceInfos);
- }
發(fā)現(xiàn)到的設(shè)備,通過(guò)Dialog進(jìn)行顯示,您可以選擇一個(gè)目標(biāo)設(shè)備進(jìn)行跨設(shè)備流轉(zhuǎn),需要在NewsDetailAbilitySlice.java的showDeviceList()中添加如下代碼:
- private void showDeviceList() {
- // 設(shè)備列表dialog
- dialog = new CommonDialog(NewsDetailAbilitySlice.this);
- dialog.setAutoClosable(true);
- dialog.setTitleText("HarmonyOS devices");
- dialog.setSize(DIALOG_SIZE_WIDTH, DIALOG_SIZE_HEIGHT);
- ListContainer devicesListContainer = new ListContainer(getContext());
- DevicesListAdapter devicesListProvider = new DevicesListProvider(devices, this);
- devicesListContainer.setItemProvider(devicesListAdapter);
- devicesListContainer.setItemClickedListener(
- (listContainer, component, position, id) -> {
- dialog.destroy()
- // 跨設(shè)備拉起FA
- startAbilityFA(devices.get(position).getDeviceId());
- });
- devicesListAdapter.notifyDataChanged();
- dialog.setContentCustomComponent(devicesListContainer);
- dialog.show();
- }

當(dāng)我們選擇某個(gè)設(shè)備的時(shí)候,被選擇的設(shè)備會(huì)拉起指定的FA頁(yè)面,被拉起的FA頁(yè)面會(huì)和發(fā)起請(qǐng)求的那一端保持一致。
9. 跨設(shè)備協(xié)同
連接Service Ability
那么跨設(shè)備協(xié)同又是如何實(shí)現(xiàn)的?發(fā)現(xiàn)的設(shè)備列表也是通過(guò)一個(gè)ListContainer來(lái)展示的,設(shè)備列表也有對(duì)應(yīng)的xml和變量聲明,這里不再贅述。對(duì)于每一個(gè)設(shè)備item,我們添加了監(jiān)聽用來(lái)進(jìn)行跨設(shè)備拉起FA,需要在NewsDetailAbilitySlice的showDeviceList()中添加startAlibityFA()方法,具體代碼如下:
- private void startAbilityFA(StringdevicesId) {
- Intent intent = new Intent();
- Operation operation =
- new Intent.OperationBuilder()
- .withDeviceId(devicesId)
- .withBundleName(getBundleName())
- .withAbilityName(SharedService.class.getName())
- // 該FLAG用于分布式跨設(shè)備場(chǎng)景
- .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
- .build();
- intent.setOperation(operation);
- boolean connectFlag =
- // 連接遠(yuǎn)端 Service Ability
- connectAbility(
- intent,
- new IAbilityConnection() {
- @Override
- public void onAbilityConnectDone(
- ElementName elementName, IRemoteObject iRemoteObject, int i) {
- INewsDemoIDL sharedManager = NewsDemoIDLStub.asInterface(iRemoteObject);
- try {
- sharedManager.tranShare(title, reads, likes, content, image);
- } catch (RemoteException e) {
- LogUtil.i(TAG, "connect successful,but have remote exception");
- }
- }
- @Override
- public void onAbilityDisconnectDone(ElementName elementName, int i) {
- disconnectAbility(this);
- }
- });
- DialogUtil.toast(
- this, connectFlag ? "Sharing succeeded!" : "Sharing failed. Please try again later.", WAIT_TIME);
- }
方法中我們?yōu)閕ntent設(shè)置了bundlename,abilityname,devicesId等參數(shù),通過(guò)connectAbility方法實(shí)現(xiàn)與遠(yuǎn)端Service Ability進(jìn)行連接,連接成功后,會(huì)在onAbilityConnectDone中調(diào)用tranShare方法將對(duì)端需要的數(shù)據(jù)傳遞過(guò)去。
遠(yuǎn)端Service Ability的定義
本端通過(guò)connectAbility連接遠(yuǎn)端的Service Ability,那么遠(yuǎn)端的Service Ability又是如何定義的?需要在SharedService.java中添加tranShare()方法,代碼如下:
- public void tranShare(String title, String reads, String likes, String content, String image) {
- Intent intent = new Intent();
- Operation operation =
- new Intent.OperationBuilder()
- .withBundleName(getBundleName())
- .withAbilityName(NewsAbility.class.getName())
- .withAction("action.detail")
- .build();
- intent.setOperation(operation);
- intent.setParam(NewsDetailAbilitySlice.INTENT_TITLE, title);
- intent.setParam(NewsDetailAbilitySlice.INTENT_READ, reads);
- intent.setParam(NewsDetailAbilitySlice.INTENT_LIKE, likes);
- intent.setParam(NewsDetailAbilitySlice.INTENT_CONTENT, content);
- intent.setParam(NewsDetailAbilitySlice.INTENT_IMAGE, image);
- startAbility(intent);
說(shuō)明:
以上代碼僅demo演示參考使用
這樣便通過(guò)startAbility方法拉起了指定的FA,并將intent攜帶的參數(shù)一并傳遞過(guò)去。
—-結(jié)束
當(dāng)前實(shí)現(xiàn)遠(yuǎn)程啟動(dòng)FA,需要至少兩個(gè)設(shè)備處于同一個(gè)分布式網(wǎng)絡(luò)中,可以通過(guò)操作如下配置實(shí)現(xiàn):
所有設(shè)備接入同一網(wǎng)絡(luò),
所有設(shè)備登陸相同華為賬號(hào),
所有設(shè)備上開啟"設(shè)置->更多連接->多設(shè)備協(xié)同 "
10. 回顧和總結(jié)
在本篇Codelab中我們介紹了應(yīng)用的主頁(yè)面和詳情頁(yè),在主頁(yè)面可以通過(guò)頂部的新聞?lì)愋颓袚Q不同類別的新聞,同時(shí)下面整個(gè)新聞列表項(xiàng)也會(huì)跟隨切換。點(diǎn)擊下方某個(gè)具體新聞item的時(shí)候,會(huì)進(jìn)行跳轉(zhuǎn)到新聞詳情頁(yè)面;在新聞詳情頁(yè)可以上下滑動(dòng)查看新聞,并且點(diǎn)擊下方分享按鈕可以實(shí)現(xiàn)FA的跨設(shè)備協(xié)同,整體效果如下圖1和圖2:


11. 恭喜你
目前你已經(jīng)成功完成了Codelab并且學(xué)到了:
如何使用ListContainer等常用控件
如何進(jìn)行布局編寫及頁(yè)面跳轉(zhuǎn)
如何進(jìn)行設(shè)備發(fā)現(xiàn)以及FA的跨設(shè)備協(xié)同
12. 參考
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)