手把手教HDC2021趣味闯关赛平行视界服务流转

开发
此帖从空白项目开始,一步步教你如何在项目里,学到列表显示,平行视界,服务卡片,服务流转各知识点。

[[434763]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

一、前言

上一篇 轻松玩转HDC2021趣味闯关赛平行视界服务流转 帖子里是基于Codelabs里Java电影卡片,平行视界Sample集成的,此帖从空白项目开始,一步步教你如何在项目里,学到列表显示,平行视界,服务卡片,服务流转各知识点。下面大慨说一下项目的开发流程:

实现List显示, 点击某项跳转到RightAbility界面

添加JS服务卡片, 点击跳转到List列表

平行视界, 点击List列表, 左边显示列表,右边显示详情图片

服务流转, 在详情,点击连接图标, 选择流转设备; 再点击流转图标==

二、实现效果

B站视频:https://www.bilibili.com/video/BV1tL4y1q7A6/

手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区

三、工程搭建

打开DevEco Studio 3.0.0.600开发工具, 点击菜单File -> New -> New Project, 弹出以下框,按截图选择创建:

手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区

下一步后的界面以下,请按照标注操作。

手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区

空模板项目到此,就创建完成了,下面我们来按照上面说的步骤一步一步来完成。

四、工程讲解

1. 实现List显示, 点击某项跳转到RightAbility界面

首先把List列表显示出来,下面是List列表的XML布局文件,由于List列表项是数据驱动的,这里只提供List容器,并给予id就可以。

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_parent" 
  5.     ohos:width="match_parent" 
  6.     ohos:alignment="center" 
  7.     ohos:orientation="vertical"
  8.     <ListContainer 
  9.         ohos:id="$+id:list" 
  10.         ohos:height="match_parent" 
  11.         ohos:width="match_parent" 
  12.         ohos:orientation="vertical"/> 
  13. </DirectionalLayout> 

 从上面效果图可以看出,列表项左边显示图片,右边显示文字,下面有一条分割线,XML布局文件以下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_content" 
  5.     ohos:width="match_parent" 
  6.     ohos:orientation="vertical"
  7.     <DirectionalLayout 
  8.         ohos:height="100vp" 
  9.         ohos:width="match_parent" 
  10.         ohos:padding="10vp" 
  11.         ohos:orientation="horizontal"
  12.         <Image 
  13.             ohos:id="$+id:img" 
  14.             ohos:height="match_parent" 
  15.             ohos:scale_mode="zoom_center" 
  16.             ohos:width="120vp"></Image> 
  17.         <Text 
  18.             ohos:id="$+id:title" 
  19.             ohos:height="match_parent" 
  20.             ohos:width="match_content" 
  21.             ohos:padding="5vp" 
  22.             ohos:text_size="16fp" 
  23.             ohos:left_margin="10vp"/> 
  24.     </DirectionalLayout> 
  25.     <Component 
  26.         ohos:height="1vp" 
  27.         ohos:width="match_parent" 
  28.         ohos:background_element="#CCCCCC"/> 
  29. </DirectionalLayout> 

 List列表的页面布局就说完了,下面来说一下Java代码:先介绍一下列表项的实体类,也就两个属性,一个是图片,一个是标题

  1. import ohos.media.image.PixelMap; 
  2.  
  3. public class Item { 
  4.     // 显示图片 
  5.     private PixelMap img; 
  6.     // 显示每项标题 
  7.     private String title; 
  8.  
  9.     public PixelMap getImg() { 
  10.         return img; 
  11.     } 
  12.     public void setImg(PixelMap img) { 
  13.         this.img = img; 
  14.     } 
  15.     public String getTitle() { 
  16.         return title; 
  17.     } 
  18.     public void setTitle(String title) { 
  19.         this.title = title; 
  20.     } 

下面介绍一下List列表的核心部分就是适配器类的实现:大部分代码都有注释,适配器类首先要继承BaseItemProvider 基础类,然后实现里面相应的方法。

  1. /** 
  2.  * 列表适配器类 
  3.  */ 
  4. public class ListAdapter extends BaseItemProvider { 
  5.  
  6.     // 上下文 
  7.     private static Context context; 
  8.     // 数据项列表 
  9.     private List<Item> items; 
  10.     // 自定义事件处理 
  11.     private MyEventHandle myEventHandle; 
  12.  
  13.  
  14.     /** 
  15.      * 构造方法 
  16.      * @param items 
  17.      * @param context 
  18.      */ 
  19.     public ListAdapter(List<Item> items, Context context) { 
  20.         this.items = items == null ? new ArrayList() : items; 
  21.         this.context = context; 
  22.     } 
  23.     /** 
  24.      * 获取列表有多少项 
  25.      * @return 
  26.      */ 
  27.     @Override 
  28.     public int getCount() { 
  29.         return items == null ? 0 : items.size(); 
  30.     } 
  31.     /** 
  32.      * 获取当前项数据 
  33.      * @param i 
  34.      * @return 
  35.      */ 
  36.     @Override 
  37.     public Item getItem(int i) { 
  38.         return this.items.get(i); 
  39.     } 
  40.     /** 
  41.      * 获取当前Id 
  42.      * @param i 
  43.      * @return 
  44.      */ 
  45.     @Override 
  46.     public long getItemId(int i) { 
  47.         return i; 
  48.     } 
  49.     /** 
  50.      * 获取组件内容 
  51.      * @param i 
  52.      * @param component 
  53.      * @param componentContainer 
  54.      * @return 
  55.      */ 
  56.     @Override 
  57.     public Component getComponent(int i, Component component, ComponentContainer componentContainer) { 
  58.         ViewHolder viewHolder = null
  59.         Component cmp = component; 
  60.         if (cmp == null) { 
  61.             cmp = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item, nullfalse); 
  62.             // 初始化项布局 
  63.             viewHolder = new ViewHolder(); 
  64.             // 获取图片组件 
  65.             viewHolder.img = (Image)cmp.findComponentById(ResourceTable.Id_img); 
  66.             // 获取标题组件 
  67.             viewHolder.title = (Text)cmp.findComponentById(ResourceTable.Id_title); 
  68.             // 缓存起来 
  69.             cmp.setTag(viewHolder); 
  70.         } else { 
  71.             viewHolder = (ViewHolder) cmp.getTag(); 
  72.         } 
  73.  
  74.         viewHolder.img.setPixelMap(items.get(i).getImg()); 
  75.         viewHolder.title.setText(items.get(i).getTitle()); 
  76.         viewHolder.img.setClickedListener(listener -> itemClick(i)); 
  77.         viewHolder.title.setClickedListener(listener -> itemClick(i)); 
  78.  
  79.         return cmp; 
  80.     } 
  81.     public void replace(Collection<Item> listConstructor) { 
  82.         if (listConstructor == null) { 
  83.             return
  84.         } 
  85.         this.items = null
  86.         // 重新初始化listContainer中的数据 
  87.         this.items = new ArrayList<>(0); 
  88.         // 将重新得到的项数据放到listContainer中 
  89.         this.items.addAll(listConstructor); 
  90.         // 刷新listContainer,调用getComponent方法重新设置页面元素布局 
  91.         notifyDataChanged(); 
  92.     } 
  93.     /** 
  94.      * 内部类,封装列表项组件 
  95.      */ 
  96.     private static class ViewHolder { 
  97.         // 显示图片 
  98.         Image img; 
  99.         // 显示标题 
  100.         Text title; 
  101.     } 
  102.     /** 
  103.      * 点击图片或标题事件 
  104.      * @param index 
  105.      */ 
  106.     private void itemClick(int index) { 
  107.         // 初始化处理程序 
  108.         initHandler(); 
  109.         // 获取内部事件 
  110.         InnerEvent event = InnerEvent.get(1, 0, index); 
  111.         myEventHandle.sendEvent(event); 
  112.     } 
  113.     /** 
  114.      * 初始化处理程序 
  115.      */ 
  116.     private void initHandler() { 
  117.         EventRunner runner = EventRunner.getMainEventRunner(); 
  118.         if (runner == null) { 
  119.             return
  120.         } 
  121.         myEventHandle = new MyEventHandle(runner); 
  122.     } 
  123.     /** 
  124.      * 自定义处理事件 
  125.      */ 
  126.     public static class MyEventHandle extends EventHandler { 
  127.         MyEventHandle(EventRunner runner) throws IllegalArgumentException { 
  128.             super(runner); 
  129.         } 
  130.  
  131.         @Override 
  132.         protected void processEvent(InnerEvent event) { 
  133.             super.processEvent(event); 
  134.             int eventId = event.eventId; 
  135.             int index = (Integer) event.object; 
  136.             if (eventId == 1) { 
  137.                 IntentParams intentParams = new IntentParams(); 
  138.                 intentParams.setParam("index"index); // 选择列表项下标 
  139.                 // 跳转到 RightAbility 分屏 
  140.                 Intent intent = new Intent(); 
  141.                 intent.setParams(intentParams); 
  142.                 ElementName element = new ElementName("", context.getBundleName(), RightAbility.class.getName()); 
  143.                 intent.setElement(element); 
  144.                 context.startAbility(intent, 0); 
  145.             } 
  146.         } 
  147.     } 

项目用的数据是静态数据,在一个Utils封装好的,以下:

  1. public class Utils { 
  2.     private static final HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP, 0xD001400, "Utils"); 
  3.  
  4.     private static final List<Integer> PICTURE_IDS = Arrays.asList(ResourceTable.Media_1, 
  5.             ResourceTable.Media_2, ResourceTable.Media_3, 
  6.             ResourceTable.Media_4, ResourceTable.Media_5, 
  7.             ResourceTable.Media_6, ResourceTable.Media_7, 
  8.             ResourceTable.Media_8, ResourceTable.Media_9, 
  9.             ResourceTable.Media_10); 
  10.  
  11.     private static List<PixelMap> resourcePixelMaps; 
  12.  
  13.     public static void transResourceIdsToListOnce(Context context) { 
  14.         resourcePixelMaps = new ArrayList<>(0); 
  15.         // Set the pixel map 
  16.         for (int index: PICTURE_IDS) { 
  17.             InputStream source = null
  18.             ImageSource imageSource; 
  19.             try { 
  20.                 source = context.getResourceManager().getResource(index); 
  21.                 imageSource = ImageSource.create(source, null); 
  22.                 resourcePixelMaps.add(imageSource.createPixelmap(null)); 
  23.             } catch (IOException | NotExistException e) { 
  24.                 HiLog.error(TAG, "Get Resource PixelMap error"); 
  25.             } finally { 
  26.                 try { 
  27.                     assert source != null
  28.                     source.close(); 
  29.                 } catch (IOException e) { 
  30.                     HiLog.error(TAG, "getPixelMap source close error"); 
  31.                 } 
  32.             } 
  33.         } 
  34.     } 
  35.  
  36.     /** 
  37.      * 封装列表项数据 
  38.      * @return 
  39.      */ 
  40.     public static List<Item> getItems() { 
  41.         List<Item> items = new ArrayList<>(); 
  42.  
  43.         int index = 1; 
  44.         for (PixelMap pixelMap : resourcePixelMaps) { 
  45.             Item item = new Item(); 
  46.             item.setImg(pixelMap); 
  47.             item.setTitle("测试标题 " + index); 
  48.             items.add(item); 
  49.             index++; 
  50.         } 
  51.  
  52.         return items; 
  53.     } 
  54.  
  55.     /** 
  56.      * 根据下标获取列表项数据 
  57.      * @param index 
  58.      * @return 
  59.      */ 
  60.     public static Item getItem(int index) { 
  61.         List<Item> items = getItems(); 
  62.         return items.get(index); 
  63.     } 

在MainAbilitySlice加载显示出列表容器里的内容:

  1. public class MainAbilitySlice extends AbilitySlice { 
  2.  
  3.     // 列表容器 
  4.     private static ListContainer listContainer; 
  5.     // 列表适配器类 
  6.     private static ListAdapter listAdapter; 
  7.     // 上下文 
  8.     private static Context context; 
  9.  
  10.  
  11.     @Override 
  12.     public void onStart(Intent intent) { 
  13.         super.onStart(intent); 
  14.         super.setUIContent(ResourceTable.Layout_ability_main); 
  15.         context = getContext(); 
  16.  
  17.         // 初始化界面 
  18.         initView(); 
  19.         // 将 Media 中的图像转换为 List<PixelMap>。 使用默认大小 
  20.         Utils.transResourceIdsToListOnce(context); 
  21.         // UI线程更新列表数据 
  22.         getUITaskDispatcher().delayDispatch(() -> initData(Utils.getItems()), 10); 
  23.     } 
  24.     /** 
  25.      * 初始化界面 
  26.      */ 
  27.     private void initView() { 
  28.         // 获取List容器 
  29.         listContainer = (ListContainer) findComponentById(ResourceTable.Id_list); 
  30.         // 初始化列表适配器 
  31.         listAdapter = new ListAdapter(null, context); 
  32.         // 设置列表容器项数据提供者 
  33.         listContainer.setItemProvider(listAdapter); 
  34.  
  35.     } 
  36.     /** 
  37.      * 更新界面数据 
  38.      * @param items 
  39.      */ 
  40.     public static void initData(List<Item> items) { 
  41.         context.getUITaskDispatcher().asyncDispatch(() -> { 
  42.             listContainer.setItemProvider(listAdapter); 
  43.             listAdapter.replace(items); 
  44.         }); 
  45.     } 

这样主界面的List列表就完成了,项目用的素材图片是放在resources -> media下的,下来介绍一下点击列表项跳转到详情页面,这里我们要创建一个Page Ability, 取名为RightAbility,同时在使用平行视界时,这个Ability显示在平板的右边。

手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区

界面布局分为上下显示,上面显示标题和后面用到的服务流转图标,下面显示点击的图片。

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_parent" 
  5.     ohos:width="match_parent" 
  6.     ohos:alignment="center" 
  7.     ohos:orientation="vertical"
  8.     <DependentLayout 
  9.         ohos:id="$+id:container_title" 
  10.         ohos:height="50vp" 
  11.         ohos:padding="10vp" 
  12.         ohos:width="match_parent"
  13.         <Text 
  14.             ohos:id="$+id:right_title" 
  15.             ohos:height="match_parent" 
  16.             ohos:width="match_content" 
  17.             ohos:padding="5vp" 
  18.             ohos:text_size="16fp" 
  19.             ohos:left_margin="10vp"/> 
  20.         <Image 
  21.             ohos:id="$+id:imgConnect" 
  22.             ohos:left_margin="10vp" 
  23.             ohos:right_margin="10vp" 
  24.             ohos:height="30vp" 
  25.             ohos:width="30vp" 
  26.             ohos:background_element="$media:connect" 
  27.             ohos:left_of="$id:imgCirculation"/> 
  28.         <Image 
  29.             ohos:id="$+id:imgCirculation" 
  30.             ohos:height="30vp" 
  31.             ohos:width="30vp" 
  32.             ohos:right_margin="10vp" 
  33.             ohos:background_element="$media:circulation" 
  34.             ohos:align_parent_right="true"/> 
  35.     </DependentLayout> 
  36.     <Image 
  37.         ohos:id="$+id:right_img" 
  38.         ohos:height="match_parent" 
  39.         ohos:scale_mode="zoom_center" 
  40.         ohos:width="match_parent"></Image> 
  41. </DirectionalLayout> 

在新Page Ability接收到跳转过来的参数,显示相应的标题和图片。

  1. public class RightAbilitySlice extends AbilitySlice { 
  2.  
  3.     private static Context context;         // 上下文 
  4.     private static int paramIndex;          // 页面跳转参数 
  5.  
  6.  
  7.     @Override 
  8.     public void onStart(Intent intent) { 
  9.         super.onStart(intent); 
  10.         super.setUIContent(ResourceTable.Layout_ability_right); 
  11.         context = getContext(); 
  12.  
  13.         // 如果页面跳转参数index为空, 默认为0 
  14.         paramIndex = intent.getIntParam("index", 0); 
  15.         Item item = Utils.getItem(paramIndex); 
  16.  
  17.         // 初始化界面 
  18.         initView(item); 
  19.        
  20.     } 
  21.     private void initView(Item item) { 
  22.         Image img = (Image)findComponentById(ResourceTable.Id_right_img); 
  23.         img.setPixelMap(item.getImg()); 
  24.  
  25.         Text title = (Text)findComponentById(ResourceTable.Id_right_title); 
  26.         title.setText(item.getTitle()); 
  27.  
  28.         Image btnSelect = (Image)findComponentById(ResourceTable.Id_imgConnect); 
  29.         Image btnShare = (Image)findComponentById(ResourceTable.Id_imgCirculation); 
  30.  
  31.         btnSelect.setClickedListener(va -> { 
  32.             // 打开设备选择框(连接) 
  33.             //deviceDialog.showDeviceList(); 
  34.         }); 
  35.         btnShare.setClickedListener(va -> { 
  36.             // 流转 
  37.             //circulation(); 
  38.         }); 
  39.     } 

添加JS服务卡片, 点击跳转到List列表。

先创建一个JS服务卡片,步骤以下:

手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区
手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区
手把手教HDC2021趣味闯关赛平行视界服务流转-鸿蒙HarmonyOS技术社区

默认服务卡片里面内容,不是我要的效果,我简单修改一下后:

  1. <div class="card_root_layout"
  2.     <div class="button_containers"
  3.         <div class="item_first_container"
  4.             <div class="button_left"
  5.                 <image src="/common/images/1.jpg" onclick="routerEvent"></image> 
  6.             </div> 
  7.             <div class="button_right"
  8.                 <image src="/common/images/2.jpg" onclick="routerEvent"></image> 
  9.             </div> 
  10.         </div> 
  11.         <div class="item_second_container"
  12.             <div class="button_left"
  13.                 <image src="/common/images/3.jpg" onclick="routerEvent"></image> 
  14.             </div> 
  15.             <div class="button_right"
  16.                 <image src="/common/images/4.jpg" onclick="routerEvent"></image> 
  17.             </div> 
  18.         </div> 
  19.     </div> 
  20. </div> 
  1. .card_root_layout { 
  2.     flex-direction: column
  3.     align-items: center; 
  4.     justify-content: center; 
  5.     width: 100%; 
  6.     height: 100%; 
  7.     padding: 10px; 
  8.     background-color: #FFFFFF; 
  9. .button_containers { 
  10.     flex-direction: column
  11.     align-items: center; 
  12.     justify-content: center; 
  13. .item_first_container { 
  14.     flex-weight: 0.4; 
  15.     flex-direction: row; 
  16.     align-items: center; 
  17.     justify-content: center; 
  18. .item_second_container { 
  19.     flex-weight: 0.4; 
  20.     flex-direction: row; 
  21.     align-items: center; 
  22.     justify-content: center; 
  23. .button_left { 
  24.     flex-weight: 0.5; 
  25.     flex-direction: column
  26.     align-items: center; 
  27.     justify-content: center; 
  28.     padding: 4px; 
  29. .button_right { 
  30.     flex-weight: 0.5; 
  31.     flex-direction: column
  32.     align-items: center; 
  33.     justify-content: center; 
  34.     padding: 4px; 
  1.   "actions": { 
  2.     "routerEvent": { 
  3.       "action""router"
  4.       "abilityName""com.army.study.MainAbility" 
  5.     } 
  6.   } 

简单的服务卡片就修改好了,点击服务卡片,跳转到List列表界面。

平行视界, 点击List列表, 左边显示列表,右边显示详情图片。

实现平行视界,注意三点就可以了,第一点,平行视界目前只能在两个Java Page Ability实现,第二点在resources -> rawfile目录下添加一个文件easygo.json, 第三点修改config.json配置,就可以了,下面我们就一点一点来完成平行视界效果。

第一点:上面已经创建好两个Java Page Ability了,一个是MainAbility, 一个是RightAbility。

第二点:添加easygo.json内容为:

  1.   "easyGoVersion""1.0"
  2.   "client""com.army.study",  // 保持和config.json bundleName一致 
  3.   "logicEntities": [ 
  4.     { 
  5.       "head": { 
  6.         "function""magicwindow"
  7.         "required""true" 
  8.       }, 
  9.       "body": { 
  10.         "mode""1"
  11.         "abilityPairs": [ 
  12.           { 
  13.             "from""com.army.study.MainAbility",  // 显示在平行视界左边的列表页面 
  14.             "to""com.army.study.RightAbility"    // 显示在平行视界右边的详情页面 
  15.           } 
  16.         ], 
  17.  
  18.         "UX": { 
  19.           "isDraggable""true"
  20.           "supportRotationUxCompat""true"
  21.           "supportDraggingToFullScreen""ALL" 
  22.         } 
  23.       } 
  24.     } 
  25.   ] 

第三点:修改config.json在moudle节点下添加以下:

  1. "metaData": { 
  2.    "customizeData": [ 
  3.      { 
  4.        "name""EasyGoClient"
  5.        "value""true" 
  6.      } 
  7.    ] 
  8.  } 

 平行视界效果就完成了。

服务流转, 在详情,点击连接图标, 选择流转设备; 再点击流转图标。

  1. 服务流转也是有几点注意的,第一点当然就是授权了,除了在config.json配置了权限申请,还要在应用入口加上动态授权,第二点就是实现流转的Abitily和AbilitySlic都要实现IAbilityContinuation接口,第三点就是显示当然环境下,在线设备可以流转到的设备,这里使用到了Codelabs平行视界Sample里封装好的DeviceDialog类,里面使用的流转任务管理服务管理类IContinuationRegisterManager, 简化了很多代码。下面就开始一 一介绍吧。 

 第一点授权,在config.json里module节点下添加以下配置:

  1. "reqPermissions": [ 
  2.       { 
  3.         "name""ohos.permission.DISTRIBUTED_DATASYNC"
  4.         "usedScene"
  5.         { 
  6.           "ability": [ 
  7.             "com.army.study.MainAbility"
  8.             "com.army.study.RightAbility" 
  9.           ], 
  10.           "when""always" 
  11.         } 
  12.       }, 
  13.       { 
  14.         "name""ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
  15.         "usedScene"
  16.         { 
  17.           "ability": [ 
  18.             "com.army.study.MainAbility"
  19.             "com.army.study.RightAbility" 
  20.           ], 
  21.           "when""always" 
  22.         } 
  23.       } 
  24.     ] 

在应用入口MainAbility里onStart()方法添加动态授权:

  1. // 声明跨端迁移访问的权限 
  2. requestPermissionsFromUser(new String[]{SystemPermission.DISTRIBUTED_DATASYNC}, 0); 

 第二点在RightAbility和RightAbilitySlice多实现IAbilityContinuation接口,其实RightAbility实现接口后,在实现方法里面返回true就可以,具体逻辑是在RightAbilitySlice中实现。

  1. public class RightAbility extends Ability implements IAbilityContinuation { 
  2.     @Override 
  3.     public void onStart(Intent intent) { 
  4.         super.onStart(intent); 
  5.         super.setMainRoute(RightAbilitySlice.class.getName()); 
  6.     } 
  7.     @Override 
  8.     public boolean onStartContinuation() { 
  9.         return true
  10.     } 
  11.     @Override 
  12.     public boolean onSaveData(IntentParams intentParams) { 
  13.         return true
  14.     } 
  15.     @Override 
  16.     public boolean onRestoreData(IntentParams intentParams) { 
  17.         return true
  18.     } 
  19.     @Override 
  20.     public void onCompleteContinuation(int i) { 
  21.     } 
  1. public class RightAbilitySlice extends AbilitySlice implements IAbilityContinuation { 
  2.  
  3.     private boolean isCirculation = false;  // 是否流转中 
  4.     private static String selectDeviceId;   // 选择的设备id 
  5.     private DeviceDialog deviceDialog;      // 设备选择 
  6.  
  7.     private static Context context;         // 上下文 
  8.     private static int paramIndex;          // 页面跳转参数 
  9.     private static int removeIndex;         // 流转参数 
  10.  
  11.     @Override 
  12.     public void onStart(Intent intent) { 
  13.         super.onStart(intent); 
  14.         super.setUIContent(ResourceTable.Layout_ability_right); 
  15.         context = getContext(); 
  16.  
  17.         // 如果页面跳转参数index为空,说明是流转过来参数, 使用流转removeIndex 
  18.         paramIndex = intent.getIntParam("index", removeIndex); 
  19.         Item item = Utils.getItem(paramIndex); 
  20.  
  21.         // 初始化界面 
  22.         initView(item); 
  23.         // 初始化设备选择 
  24.         deviceDialog = new DeviceDialog(getContinuationRegisterManager(),RightAbilitySlice.this); 
  25.     } 
  26.     private void initView(Item item) { 
  27.         Image img = (Image)findComponentById(ResourceTable.Id_right_img); 
  28.         img.setPixelMap(item.getImg()); 
  29.  
  30.         Text title = (Text)findComponentById(ResourceTable.Id_right_title); 
  31.         title.setText(item.getTitle()); 
  32.  
  33.         Image btnSelect = (Image)findComponentById(ResourceTable.Id_imgConnect); 
  34.         Image btnShare = (Image)findComponentById(ResourceTable.Id_imgCirculation); 
  35.  
  36.         btnSelect.setClickedListener(va -> { 
  37.             // 打开设备选择框(连接) 
  38.             deviceDialog.showDeviceList(); 
  39.         }); 
  40.         btnShare.setClickedListener(va -> { 
  41.             // 流转 
  42.             circulation(); 
  43.         }); 
  44.     } 
  45.     /** 
  46.      * 流转 
  47.      */ 
  48.     private void circulation() { 
  49.         if (isCirculation) { 
  50.             Utils.createToastDialog(context, "正在流转,请稍后再试!"); 
  51.             return
  52.         } 
  53.         if (selectDeviceId == null || "".equals(selectDeviceId)) { 
  54.             // 选择设备以后才能流转(迁移) 
  55.             Utils.createToastDialog(context, "请选择连接设备后进行流转操作!"); 
  56.             return
  57.         } 
  58.         isCirculation = true
  59.  
  60.         continueAbility(selectDeviceId); 
  61.     } 
  62.  
  63.     /** 
  64.      * 设置选择设备Id 
  65.      * @param deviceId 
  66.      */ 
  67.     public static void setDeviceId(String deviceId) { 
  68.         selectDeviceId = deviceId; 
  69.     } 
  70.     @Override 
  71.     public void onActive() { 
  72.         super.onActive(); 
  73.     } 
  74.     @Override 
  75.     public void onForeground(Intent intent) { 
  76.         super.onForeground(intent); 
  77.     } 
  78.     @Override 
  79.     public boolean onStartContinuation() { 
  80.         return true
  81.     } 
  82.     @Override 
  83.     public boolean onSaveData(IntentParams intentParams) { 
  84.         // 流转前保存index 
  85.         intentParams.setParam("removeIndex", paramIndex); 
  86.         return true
  87.     } 
  88.     @Override 
  89.     public boolean onRestoreData(IntentParams intentParams) { 
  90.         // 获取流转过来的index 
  91.         removeIndex = Integer.parseInt(intentParams.getParam("removeIndex").toString()); 
  92.         return true
  93.     } 
  94.     @Override 
  95.     public void onCompleteContinuation(int i) { 
  96.     } 

这里说一下详情页参数index,有两个地方传递了,一个是在单设备时,从列表点击跳转到详情页,传递了参数index,另一个是服务流转到另一个设备时,流转前通过onSaveData保存index,到另一个设备通过onRestoreData获取到流转过来的index。

第三点就是使用封装好的DeviceDialog类,代码不多,我都添加注释了,把这个类理解了,分布式工作就省了不少代码了。

  1. public class DeviceDialog { 
  2.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "设备对话框"); 
  3.     // 上下文 
  4.     private final Context context; 
  5.     // 获取流转任务管理服务管理类 
  6.     private final IContinuationRegisterManager continuationRegisterManager; 
  7.     // 注册传输任务管理服务后返回的能力令牌 
  8.     private int abilityToken; 
  9.     // 用户在设备列表中选择设备后返回的设备ID 
  10.     private String selectDeviceId; 
  11.  
  12.     /** 
  13.      * 初始化设备对话框,设置传输任务管理服务管理类,并注册传输任务管理服务管理类。 
  14.      * @param continuationRegisterManager 
  15.      * @param slice 
  16.      */ 
  17.     public DeviceDialog(IContinuationRegisterManager continuationRegisterManager, Context slice) { 
  18.         this.continuationRegisterManager = continuationRegisterManager; 
  19.         this.context = slice; 
  20.         // 注册流转任务管理服务管理类 
  21.         registerManager(); 
  22.     } 
  23.  
  24.     /** 
  25.      * 注册流转任务管理服务管理类 
  26.      */ 
  27.     private void registerManager() { 
  28.         // 增加过滤条件 
  29.         ExtraParams params = new ExtraParams(); 
  30.         String[] devTypes = new String[]{ExtraParams.DEVICETYPE_SMART_PAD, ExtraParams.DEVICETYPE_SMART_PHONE}; 
  31.         params.setDevType(devTypes); 
  32.         continuationRegisterManager.register(context.getBundleName(), params, callback, requestCallback); 
  33.     } 
  34.     // 设置流转任务管理服务设备状态变更的回调 
  35.     private final IContinuationDeviceCallback callback = new IContinuationDeviceCallback() { 
  36.         @Override 
  37.         public void onDeviceConnectDone(String str, String str1) { 
  38.             // 在用户选择设备后设置设备ID 
  39.             selectDeviceId = str; 
  40.             continuationRegisterManager.updateConnectStatus(abilityToken, selectDeviceId, 
  41.                     DeviceConnectState.CONNECTED.getState(), null); 
  42.             // 返回设备ID 
  43.             returnDeviceId(); 
  44.         } 
  45.  
  46.         @Override 
  47.         public void onDeviceDisconnectDone(String str) { 
  48.         } 
  49.     }; 
  50.     // 设置注册流转任务管理服务回调 
  51.     private final RequestCallback requestCallback = new RequestCallback() { 
  52.         @Override 
  53.         public void onResult(int result) { 
  54.             abilityToken = result; 
  55.         } 
  56.     }; 
  57.     /** 
  58.      * 返回设备ID 
  59.      */ 
  60.     private void returnDeviceId() { 
  61.         HiLog.info(LABEL_LOG, "deviceid::" + selectDeviceId); 
  62.         // 将选择设备Id, 告诉RightAbilitySlice 
  63.         RightAbilitySlice.setDeviceId(selectDeviceId); 
  64.     } 
  65.  
  66.     /** 
  67.      * 打开设备选择框 
  68.      * 
  69.      * @since 2021-09-10 
  70.      */ 
  71.     public void showDeviceList() { 
  72.         // 设置过滤设备类型 
  73.         ExtraParams params = new ExtraParams(); 
  74.         String[] devTypes = new String[]{ExtraParams.DEVICETYPE_SMART_PAD, ExtraParams.DEVICETYPE_SMART_PHONE}; 
  75.         params.setDevType(devTypes); 
  76.         // 注册 
  77.         continuationRegisterManager.register(context.getBundleName(), params, callback, requestCallback); 
  78.         // 显示选择设备列表 
  79.         continuationRegisterManager.showDeviceList(abilityToken, params, null); 
  80.     } 
  81.  
  82.     /** 
  83.      * 断开流转任务管理服务 
  84.      * 
  85.      * @since 2021-09-10 
  86.      */ 
  87.     public void clearRegisterManager() { 
  88.         // 解注册流转任务管理服务 
  89.         continuationRegisterManager.unregister(abilityToken, null); 
  90.         // 断开流转任务管理服务连接 
  91.         continuationRegisterManager.disconnect(); 
  92.     } 

到这里就介绍完我说的四个步骤了,帖子有些长,要有点耐心看才行,如果不能集中看完,也可以直接同步源码,先运行起来,看看效果,然后再一步一步的去理解就,最后合在一起就成了。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-11-08 10:20:48

鸿蒙HarmonyOS应用

2009-11-06 10:44:31

Visual Stud

2022-09-14 17:12:15

flowable源码DEMO

2020-11-10 09:00:00

JavaMule ESB开发

2010-09-02 10:50:17

时间同步服务器

2010-07-07 10:24:46

Python多线程

2009-10-21 10:47:03

Siliverligh

2010-08-18 09:15:45

路由器网络诊断

2020-09-23 07:00:00

Selenium We架构

2020-09-04 10:14:02

Linux驱动7内核

2021-02-04 11:53:49

Linuxplatform总线

2010-03-10 11:16:31

服务器DIY

2020-02-21 19:54:09

HTTPS 配置手把手教

2020-09-27 06:59:59

IO系统Linux

2010-09-14 09:24:27

家庭无线网络

2020-02-21 10:45:06

运维架构技术

2010-08-26 09:24:59

路由器网络诊断

2021-10-29 15:34:45

鸿蒙HarmonyOS应用

2010-04-02 16:51:09

虚拟机安装linux

2011-02-22 17:42:26

点赞
收藏

51CTO技术栈公众号