HarmonyOS 分布式之仿抖音应用

HarmonyOS 分布式之仿抖音应用

作者:梁青松 2021-10-21 10:03:09

开发

分布式

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

[[430075]]

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

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

https://harmonyos.IDC.NET

项目介绍

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

效果演示

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

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

项目结构

主要代码

1、上下滑动页面

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

  1. import ohos.aafwk.ability.AbilitySlice; 
  2. import ohos.aafwk.content.Intent; 
  3. import ohos.agp.components.*; 
  4.  
  5. import java.util.ArrayList; 
  6. import java.util.List; 
  7.  
  8. public class MainAbilitySlice extends AbilitySlice { 
  9.     @Override 
  10.     public void onStart(Intent intent) { 
  11.         super.onStart(intent); 
  12.         super.setUIContent(ResourceTable.Layout_ability_main); 
  13.         // 查找滑动页面组件 
  14.         PageSlider pageSlider = (PageSlider) findComponentById(ResourceTable.Id_pageSlider); 
  15.         // 设置滑动方向为上下滑动 
  16.         pageSlider.setOrientation(Component.VERTICAL); 
  17.         // 集合测试数据 
  18.         List<String> listData=new ArrayList<>(); 
  19.         listData.add("第一页"); 
  20.         listData.add("第二页"); 
  21.         listData.add("第三页"); 
  22.          
  23.         // 设置页面适配器 
  24.         pageSlider.setProvider(new PageSliderProvider() { 
  25.             /** 
  26.              * 获取当前适配器中可用视图的数量 
  27.              */ 
  28.             @Override 
  29.             public int getCount() { 
  30.                 return listData.size(); 
  31.             } 
  32.             /** 
  33.              * 创建页面 
  34.              */ 
  35.             @Override 
  36.             public Object createPageInContainer(ComponentContainer container, int position) { 
  37.                 // 查找布局 
  38.                 Component component = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_item_page, nullfalse); 
  39.                 Text textContent = (Text) component.findComponentById(ResourceTable.Id_text_item_page_content); 
  40.                 // 设置数据 
  41.                 textContent.setText(listData.get(position)); 
  42.                 // 添加到容器中 
  43.                 container.addComponent(component); 
  44.                 return component; 
  45.             } 
  46.             /** 
  47.              * 销毁页面 
  48.              */ 
  49.             @Override 
  50.             public void destroyPageFromContainer(ComponentContainer container, int position, Object object) { 
  51.                 // 从容器中移除 
  52.                 container.removeComponent((Component) object); 
  53.             } 
  54.             /** 
  55.              * 检查页面是否与对象匹配 
  56.              */ 
  57.             @Override 
  58.             public boolean isPageMatchToObject(Component page, Object object) { 
  59.                 return true
  60.             } 
  61.         }); 
  62.  
  63.         // 添加页面改变监听器 
  64.         pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() { 
  65.             /** 
  66.              * 页面滑动时调用 
  67.              */ 
  68.             @Override 
  69.             public void onPageSliding(int itemPos, float itemPosOffset, int itemPosOffsetPixels) {} 
  70.             /** 
  71.              * 当页面滑动状态改变时调用 
  72.              */ 
  73.             @Override 
  74.             public void onPageSlideStateChanged(int state) {} 
  75.             /** 
  76.              * 选择新页面时回调 
  77.              */ 
  78.             @Override 
  79.             public void onPageChosen(int itemPos) { 
  80.                 // 在此方法下,切换页面获取当前页面的视频源,进行播放 
  81.                 String data = listData.get(itemPos); 
  82.             } 
  83.         }); 
  84.     } 

2、播放视频

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

  1. import ohos.aafwk.ability.AbilitySlice; 
  2. import ohos.aafwk.content.Intent; 
  3. import ohos.agp.components.surfaceprovider.SurfaceProvider; 
  4. import ohos.agp.graphics.SurfaceOps; 
  5. import ohos.global.resource.RawFileDescriptor; 
  6. import ohos.media.common.Source; 
  7. import ohos.media.player.Player; 
  8.  
  9. import java.io.IOException; 
  10.  
  11. public class MainAbilitySlice extends AbilitySlice { 
  12.     // 视频路径 
  13.     private final String videoPath = "resources/rawfile/HarmonyOS.mp4"
  14.     // 播放器 
  15.     private Player mPlayer; 
  16.  
  17.     @Override 
  18.     public void onStart(Intent intent) { 
  19.         super.onStart(intent); 
  20.         super.setUIContent(ResourceTable.Layout_ability_main); 
  21.         // 初始化播放器 
  22.         mPlayer = new Player(getContext()); 
  23.         // 查找视频窗口组件 
  24.         SurfaceProvider surfaceProvider = (SurfaceProvider) findComponentById(ResourceTable.Id_surfaceProvider); 
  25.         // 设置视频窗口在顶层 
  26.         surfaceProvider.pinToZTop(true); 
  27.         // 设置视频窗口操作监听 
  28.         if (surfaceProvider.getSurfaceOps().isPresent()) { 
  29.             surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() { 
  30.                 /** 
  31.                  * 创建视频窗口 
  32.                  */ 
  33.                 @Override 
  34.                 public void surfaceCreated(SurfaceOps holder) { 
  35.                     try { 
  36.                         RawFileDescriptor fileDescriptor = getResourceManager().getRawFileEntry(videoPath).openRawFileDescriptor(); 
  37.                         Source source = new Source(fileDescriptor.getFileDescriptor(), 
  38.                                 fileDescriptor.getStartPosition(), 
  39.                                 fileDescriptor.getFileSize() 
  40.                         ); 
  41.                         // 设置媒体文件 
  42.                         mPlayer.setSource(source); 
  43.                         // 设置播放窗口 
  44.                         mPlayer.setVideoSurface(holder.getSurface()); 
  45.                         // 循环播放 
  46.                         mPlayer.enableSingleLooping(true); 
  47.                         // 准备播放环境并缓冲媒体数据 
  48.                         mPlayer.prepare(); 
  49.                         // 开始播放 
  50.                         mPlayer.play(); 
  51.                     } catch (IOException e) { 
  52.                         e.printStackTrace(); 
  53.                     } 
  54.  
  55.                 } 
  56.                 /** 
  57.                  * 视频窗口改变 
  58.                  */ 
  59.                 @Override 
  60.                 public void surfaceChanged(SurfaceOps holder, int format, int width, int height) {} 
  61.                 /** 
  62.                  * 视频窗口销毁 
  63.                  */ 
  64.                 @Override 
  65.                 public void surfaceDestroyed(SurfaceOps holder) {} 
  66.             }); 
  67.         } 
  68.     } 
  69.  
  70.     @Override 
  71.     protected void onStop() { 
  72.         super.onStop(); 
  73.         // 页面销毁,释放播放器 
  74.         if (mPlayer != null) { 
  75.             mPlayer.stop(); 
  76.             mPlayer.release(); 
  77.         } 
  78.     } 

3、跨设备迁移示例

跨设备迁移使用IAbilityContinuation接口。

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

  1. "reqPermissions": [ 
  2.       { 
  3.         "name""ohos.permission.DISTRIBUTED_DATASYNC" 
  4.       }, 
  5.       { 
  6.         "name""ohos.permission.GET_DISTRIBUTED_DEVICE_INFO" 
  7.       }, 
  8.       { 
  9.         "name""ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE" 
  10.       } 
  11.     ] 

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

  1. import ohos.aafwk.ability.AbilitySlice; 
  2. import ohos.aafwk.ability.IAbilityContinuation; 
  3. import ohos.aafwk.content.Intent; 
  4. import ohos.aafwk.content.IntentParams; 
  5. import ohos.agp.components.Button; 
  6. import ohos.agp.components.Text; 
  7. import ohos.bundle.IBundleManager; 
  8. import ohos.distributedschedule.interwork.DeviceInfo; 
  9. import ohos.distributedschedule.interwork.DeviceManager; 
  10.  
  11. import java.util.List; 
  12.  
  13. public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation { 
  14.     private String data = ""
  15.     String PERMISSION = "ohos.permission.DISTRIBUTED_DATASYNC"
  16.  
  17.     @Override 
  18.     public void onStart(Intent intent) { 
  19.         super.onStart(intent); 
  20.         super.setUIContent(ResourceTable.Layout_ability_main); 
  21.         // 申请权限 
  22.         if (verifySelfPermission(PERMISSION) != IBundleManager.PERMISSION_GRANTED) { 
  23.             requestPermissionsFromUser(new String[]{PERMISSION}, 0); 
  24.         } 
  25.         Button button = (Button)findComponentById(ResourceTable.Id_button); 
  26.         Text text = (Text)findComponentById(ResourceTable.Id_text); 
  27.          
  28.         // 点击迁移 
  29.         button.setClickedListener(component -> { 
  30.             // 查询分布式网络中所有在线设备(不包括本地设备)的信息。 
  31.             List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE); 
  32.             if (deviceList.size()>0) { 
  33.                 // 启动迁移,指定的设备ID 
  34.                 continueAbility(deviceList.get(0).getDeviceId()); 
  35.             } 
  36.         }); 
  37.         // 显示迁移的数据 
  38.         text.setText("迁移的数据:"+data); 
  39.     } 
  40.     /** 
  41.      * 启动迁移时首次调用此方法 
  42.      * @return 是否进行迁移 
  43.      */ 
  44.     @Override 
  45.     public boolean onStartContinuation() { 
  46.         return true
  47.     } 
  48.     /** 
  49.      * 迁移时存入数据 
  50.      */ 
  51.     @Override 
  52.     public boolean onSaveData(IntentParams intentParams) { 
  53.         intentParams.setParam("data","测试数据"); 
  54.         return true
  55.     } 
  56.     /** 
  57.      * 获取迁移存入的数据,在生命周期的onStart之前执行 
  58.      */ 
  59.     @Override 
  60.     public boolean onRestoreData(IntentParams intentParams) { 
  61.         data= (String) intentParams.getParam("data"); 
  62.         return true
  63.     } 
  64.     /** 
  65.      * 迁移完成 
  66.      */ 
  67.     @Override 
  68.     public void onCompleteContinuation(int i) {} 

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

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

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

https://harmonyos.IDC.NET

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/229989.html<

(0)
运维的头像运维
上一篇2025-04-19 00:51
下一篇 2025-04-19 00:52

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注