本文使用 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); // 集合测试数据 ListlistData=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 -> { // 查询分布式网络中所有在线设备(不包括本地设备)的信息。 ListdeviceList = 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) {} }
根据上面的核心代码示例,了解实现原理,接下来便可以结合实际需求完善功能了。
责任编辑:haq
全部0条评论
快来发表一下你的评论吧 !