HarmonyOS 分布式之仿抖音应用

使用Java UI开发分布式仿抖音应用,上下滑动切换视频,评论功能,设备迁移功能:记录播放的视频页和
首页 新闻资讯 行业资讯 HarmonyOS 分布式之仿抖音应用

[[430075]]

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

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

https://harmonyos.51cto.com

项目介绍

使用Java UI开发分布式仿抖音应用,上下滑动切换视频,评论功能,设备迁移功能:记录播放的视频页和进度、评论数据。

效果演示

1.上下滑动切换视频、点击迁移图标,弹框选择在线的设备,完成视频数据的迁移。

2.点击评论图标查看评论,编辑评论内容并发送。点击迁移图标,弹框选择在线的设备,完成评论数据的迁移。

项目结构

主要代码

1、上下滑动页面

页面切换用到系统组件PageSlider,默认左右切换,设置为上下方向:setOrientation(Component.VERTICAL);

复制

import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.*;  import java.util.ArrayList; import java.util.List;  public class MainAbilitySlice extends AbilitySlice {     @Override     public void onStart(Intent intent) {         super.onStart(intent);         super.setUIContent(ResourceTable.Layout_ability_main);         // 查找滑动页面组件         PageSlider pageSlider = (PageSlider) findComponentById(ResourceTable.Id_pageSlider);         // 设置滑动方向为上下滑动         pageSlider.setOrientation(Component.VERTICAL);         // 集合测试数据         List<String> listData=new ArrayList<>();         listData.add("第一页");         listData.add("第二页");         listData.add("第三页");                  // 设置页面适配器         pageSlider.setProvider(new PageSliderProvider() {             /**              * 获取当前适配器中可用视图的数量              */             @Override             public int getCount() {                 return listData.size();             }             /**              * 创建页面              */             @Override             public Object createPageInContainer(ComponentContainer container, int position) {                 // 查找布局                 Component component = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_item_page, null, false);                 Text textContent = (Text) component.findComponentById(ResourceTable.Id_text_item_page_content);                 // 设置数据                 textContent.setText(listData.get(position));                 // 添加到容器中                 container.addComponent(component);                 return component;             }             /**              * 销毁页面              */             @Override             public void destroyPageFromContainer(ComponentContainer container, int position, Object object) {                 // 从容器中移除                 container.removeComponent((Component) object);             }             /**              * 检查页面是否与对象匹配              */             @Override             public boolean isPageMatchToObject(Component page, Object object) {                 return true;             }         });          // 添加页面改变监听器         pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() {             /**              * 页面滑动时调用              */             @Override             public void onPageSliding(int itemPos, float itemPosOffset, int itemPosOffsetPixels) {}             /**              * 当页面滑动状态改变时调用              */             @Override             public void onPageSlideStateChanged(int state) {}             /**              * 选择新页面时回调              */             @Override             public void onPageChosen(int itemPos) {                 // 在此方法下,切换页面获取当前页面的视频源,进行播放                 String data = listData.get(itemPos);             }         });     } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

2、播放视频

视频播放使用Player,视频画面窗口显示使用SurfaceProvider。

复制

import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.surfaceprovider.SurfaceProvider; import ohos.agp.graphics.SurfaceOps; import ohos.global.resource.RawFileDescriptor; import ohos.media.common.Source; import ohos.media.player.Player;  import java.io.IOException;  public class MainAbilitySlice extends AbilitySlice {     // 视频路径     private final String videoPath = "resources/rawfile/HarmonyOS.mp4";     // 播放器     private Player mPlayer;      @Override     public void onStart(Intent intent) {         super.onStart(intent);         super.setUIContent(ResourceTable.Layout_ability_main);         // 初始化播放器         mPlayer = new Player(getContext());         // 查找视频窗口组件         SurfaceProvider surfaceProvider = (SurfaceProvider) findComponentById(ResourceTable.Id_surfaceProvider);         // 设置视频窗口在顶层         surfaceProvider.pinToZTop(true);         // 设置视频窗口操作监听         if (surfaceProvider.getSurfaceOps().isPresent()) {             surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() {                 /**                  * 创建视频窗口                  */                 @Override                 public void surfaceCreated(SurfaceOps holder) {                     try {                         RawFileDescriptor fileDescriptor = getResourceManager().getRawFileEntry(videoPath).openRawFileDescriptor();                         Source source = new Source(fileDescriptor.getFileDescriptor(),                                 fileDescriptor.getStartPosition(),                                 fileDescriptor.getFileSize()                         );                         // 设置媒体文件                         mPlayer.setSource(source);                         // 设置播放窗口                         mPlayer.setVideoSurface(holder.getSurface());                         // 循环播放                         mPlayer.enableSingleLooping(true);                         // 准备播放环境并缓冲媒体数据                         mPlayer.prepare();                         // 开始播放                         mPlayer.play();                     } catch (IOException e) {                         e.printStackTrace();                     }                  }                 /**                  * 视频窗口改变                  */                 @Override                 public void surfaceChanged(SurfaceOps holder, int format, int width, int height) {}                 /**                  * 视频窗口销毁                  */                 @Override                 public void surfaceDestroyed(SurfaceOps holder) {}             });         }     }      @Override     protected void onStop() {         super.onStop();         // 页面销毁,释放播放器         if (mPlayer != null) {             mPlayer.stop();             mPlayer.release();         }     } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

3、跨设备迁移示例

跨设备迁移使用IAbilityContinuation接口。

1、在entry下的config.json配置权限

复制

"reqPermissions": [       {         "name": "ohos.permission.DISTRIBUTED_DATASYNC"       },       {         "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"       },       {         "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"       }     ]
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

2、实现IAbilityContinuation接口,说明:一个应用可能包含多个Page,仅需要在支持迁移的Page中通过以下方法实现IAbilityContinuation接口。同时,此Page所包含的所有AbilitySlice也需要实现此接口。

复制

import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.ability.IAbilityContinuation; import ohos.aafwk.content.Intent; import ohos.aafwk.content.IntentParams; import ohos.agp.components.Button; import ohos.agp.components.Text; import ohos.bundle.IBundleManager; import ohos.distributedschedule.interwork.DeviceInfo; import ohos.distributedschedule.interwork.DeviceManager;  import java.util.List;  public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation {     private String data = "";     String PERMISSION = "ohos.permission.DISTRIBUTED_DATASYNC";      @Override     public void onStart(Intent intent) {         super.onStart(intent);         super.setUIContent(ResourceTable.Layout_ability_main);         // 申请权限         if (verifySelfPermission(PERMISSION) != IBundleManager.PERMISSION_GRANTED) {             requestPermissionsFromUser(new String[]{PERMISSION}, 0);         }         Button button = (Button)findComponentById(ResourceTable.Id_button);         Text text = (Text)findComponentById(ResourceTable.Id_text);                  // 点击迁移         button.setClickedListener(component -> {             // 查询分布式网络中所有在线设备(不包括本地设备)的信息。             List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);             if (deviceList.size()>0) {                 // 启动迁移,指定的设备ID                 continueAbility(deviceList.get(0).getDeviceId());             }         });         // 显示迁移的数据         text.setText("迁移的数据:"+data);     }     /**      * 启动迁移时首次调用此方法      * @return 是否进行迁移      */     @Override     public boolean onStartContinuation() {         return true;     }     /**      * 迁移时存入数据      */     @Override     public boolean onSaveData(IntentParams intentParams) {         intentParams.setParam("data","测试数据");         return true;     }     /**      * 获取迁移存入的数据,在生命周期的onStart之前执行      */     @Override     public boolean onRestoreData(IntentParams intentParams) {         data= (String) intentParams.getParam("data");         return true;     }     /**      * 迁移完成      */     @Override     public void onCompleteContinuation(int i) {} }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

根据上面的核心代码示例,了解实现原理,接下来便可以结合实际需求完善功能了。

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

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

https://harmonyos.51cto.com

 

17    2021-10-21 10:03:09    鸿蒙 HarmonyOS 应用