#星光计划1.0# HarmonyOS 分布式之仿抖音应用 原创 精华

中软HOS小鸿
发布于 2021-10-20 09:43
浏览
7收藏

作者:梁青松

项目介绍

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

效果演示

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

#星光计划1.0# HarmonyOS 分布式之仿抖音应用-鸿蒙开发者社区

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

#星光计划1.0# HarmonyOS 分布式之仿抖音应用-鸿蒙开发者社区

项目结构

#星光计划1.0# HarmonyOS 分布式之仿抖音应用-鸿蒙开发者社区

主要代码

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);
            }
        });
    }
}

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();
        }
    }
}

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"
      }
    ]

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) {}
}

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

项目地址

https://gitee.com/liangdidi/DistributedDemo

更多原创内容请关注:开鸿 HarmonyOS 学院

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

【本文正在参与51CTO HarmonyOS技术社区创作者激励-星光计划1.0】

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
12
收藏 7
回复
举报
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

确实很像抖音,完善后肯定会是一款优秀的产品。

1
回复
2021-10-20 10:07:35
甜甜爱开发
甜甜爱开发

楼主666,这个是不是也可以参加华为的活动呀?

回复
2021-10-20 11:13:28
SummerRic
SummerRic

很赞(抱大腿

回复
2021-10-20 14:55:27
中软HOS小鸿
中软HOS小鸿 回复了 甜甜爱开发
楼主666,这个是不是也可以参加华为的活动呀?

是呀,作者参加了华为活动呢

回复
2021-11-11 20:11:34
回复
    相关推荐