作者:梁青松

项目介绍

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

效果演示

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

HarmonyOS 分布式之仿抖音应用_java


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


HarmonyOS 分布式之仿抖音应用_ico_02

项目结构

HarmonyOS 分布式之仿抖音应用_bundle_03

主要代码

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】​


HarmonyOS 分布式之仿抖音应用_ide_04