本文使用 java ui 开发分布式仿抖音应用,上下滑动切换视频,评论功能,设备迁移功能:记录播放的视频页和进度、评论数据。
效果演示
①上下滑动切换视频、点击迁移图标,弹框选择在线的设备,完成视频数据的迁移。
②点击评论图标查看评论,编辑评论内容并发送。点击迁移图标,弹框选择在线的设备,完成评论数据的迁移。
项目结构
如下图:
主要代码
①上下滑动页面
页面切换用到系统组件 pageslider:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-pageslider-0000001091933258
默认左右切换,设置为上下方向: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 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); } }); }}
②播放视频
视频播放使用 player:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-video-player-0000000000044178
视频画面窗口显示使用 surfaceprovider:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/faq-media-0000001124842486#section0235506211 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(); } }}
③跨设备迁移示例
跨设备迁移使用 iabilitycontinuation 接口:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-page-cross-device-0000001051072880
在 entry 下的 config.json 配置权限:
reqpermissions: [ { name: ohos.permission.distributed_datasync }, { name: ohos.permission.get_distributed_device_info }, { name: ohos.permission.distributed_device_state_change } ]
实现 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 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) {}}
根据上面的核心代码示例,了解实现原理,接下来便可以结合实际需求完善功能了。
不知不觉中,这些国产货已经称霸全世界!
ams双通道测量集成电路AS8510可助力实现高性能电池管理系统
开路电压形成的原因_开路电压形的实际测量
电视市场热闹非凡,大尺寸电视均价创历史新低
华为创始人任正非表示美国将在未来打击华为物联网领域
鸿蒙系统中用Java UI开发分布式仿抖音应用
华为的800V智能电驱动系统
4G+64G版魅族PRO 6s进入降价通道, 快来看看
智能显示屏为智能家居提供了细致入微的智慧服务
iOS10.3.3正式版今晨发布:iOS11正式版还有多远?那么是iOS10.3.3正式版好?还是iOS11Beta3好呢?
尼吉康强攻新能源汽车市场 首推业界“三合一混合蓄电系统”
北京大学汪国平教授表示:将VR技术应用于航空,医疗,教育产等领域
伟世通推出了DriveCoreTM及全数字化座舱解决方案
佰维SS321服务器系统盘:核心器件国产化、高能效、高可靠
CDN到底是什么
小米5c领衔,华为荣耀8青春版、魅蓝Note5、华为畅玩6X、360N5、乐MAX2等热门千元机盘点
华为云加固企业网站安全堤坝,助您业务稳定流畅
智能工厂成为制造业数字化转型主战场
风河推出新一代物联网RTOS集成虚拟化技术
大水道钢二柱散热器介绍