HarmonyOS 分布式之仿抖音應(yīng)用
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
項目介紹
使用Java UI開發(fā)分布式仿抖音應(yīng)用,上下滑動切換視頻,評論功能,設(shè)備遷移功能:記錄播放的視頻頁和進度、評論數(shù)據(jù)。
效果演示
1.上下滑動切換視頻、點擊遷移圖標,彈框選擇在線的設(shè)備,完成視頻數(shù)據(jù)的遷移。
2.點擊評論圖標查看評論,編輯評論內(nèi)容并發(fā)送。點擊遷移圖標,彈框選擇在線的設(shè)備,完成評論數(shù)據(jù)的遷移。
項目結(jié)構(gòu)
主要代碼
1、上下滑動頁面
頁面切換用到系統(tǒng)組件PageSlider,默認左右切換,設(shè)置為上下方向: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);
- // 設(shè)置滑動方向為上下滑動
- pageSlider.setOrientation(Component.VERTICAL);
- // 集合測試數(shù)據(jù)
- List<String> listData=new ArrayList<>();
- listData.add("第一頁");
- listData.add("第二頁");
- listData.add("第三頁");
- // 設(shè)置頁面適配器
- pageSlider.setProvider(new PageSliderProvider() {
- /**
- * 獲取當(dāng)前適配器中可用視圖的數(shù)量
- */
- @Override
- public int getCount() {
- return listData.size();
- }
- /**
- * 創(chuàng)建頁面
- */
- @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);
- // 設(shè)置數(shù)據(jù)
- 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;
- }
- });
- // 添加頁面改變監(jiān)聽器
- pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() {
- /**
- * 頁面滑動時調(diào)用
- */
- @Override
- public void onPageSliding(int itemPos, float itemPosOffset, int itemPosOffsetPixels) {}
- /**
- * 當(dāng)頁面滑動狀態(tài)改變時調(diào)用
- */
- @Override
- public void onPageSlideStateChanged(int state) {}
- /**
- * 選擇新頁面時回調(diào)
- */
- @Override
- public void onPageChosen(int itemPos) {
- // 在此方法下,切換頁面獲取當(dāng)前頁面的視頻源,進行播放
- 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);
- // 設(shè)置視頻窗口在頂層
- surfaceProvider.pinToZTop(true);
- // 設(shè)置視頻窗口操作監(jiān)聽
- if (surfaceProvider.getSurfaceOps().isPresent()) {
- surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceOps.Callback() {
- /**
- * 創(chuàng)建視頻窗口
- */
- @Override
- public void surfaceCreated(SurfaceOps holder) {
- try {
- RawFileDescriptor fileDescriptor = getResourceManager().getRawFileEntry(videoPath).openRawFileDescriptor();
- Source source = new Source(fileDescriptor.getFileDescriptor(),
- fileDescriptor.getStartPosition(),
- fileDescriptor.getFileSize()
- );
- // 設(shè)置媒體文件
- mPlayer.setSource(source);
- // 設(shè)置播放窗口
- mPlayer.setVideoSurface(holder.getSurface());
- // 循環(huán)播放
- mPlayer.enableSingleLooping(true);
- // 準備播放環(huán)境并緩沖媒體數(shù)據(jù)
- 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、跨設(shè)備遷移示例
跨設(shè)備遷移使用IAbilityContinuation接口。
1、在entry下的config.json配置權(quán)限
- "reqPermissions": [
- {
- "name": "ohos.permission.DISTRIBUTED_DATASYNC"
- },
- {
- "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
- },
- {
- "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
- }
- ]
2、實現(xiàn)IAbilityContinuation接口,說明:一個應(yīng)用可能包含多個Page,僅需要在支持遷移的Page中通過以下方法實現(xiàn)IAbilityContinuation接口。同時,此Page所包含的所有AbilitySlice也需要實現(xiàn)此接口。
- 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);
- // 申請權(quán)限
- 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 -> {
- // 查詢分布式網(wǎng)絡(luò)中所有在線設(shè)備(不包括本地設(shè)備)的信息。
- List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
- if (deviceList.size()>0) {
- // 啟動遷移,指定的設(shè)備ID
- continueAbility(deviceList.get(0).getDeviceId());
- }
- });
- // 顯示遷移的數(shù)據(jù)
- text.setText("遷移的數(shù)據(jù):"+data);
- }
- /**
- * 啟動遷移時首次調(diào)用此方法
- * @return 是否進行遷移
- */
- @Override
- public boolean onStartContinuation() {
- return true;
- }
- /**
- * 遷移時存入數(shù)據(jù)
- */
- @Override
- public boolean onSaveData(IntentParams intentParams) {
- intentParams.setParam("data","測試數(shù)據(jù)");
- return true;
- }
- /**
- * 獲取遷移存入的數(shù)據(jù),在生命周期的onStart之前執(zhí)行
- */
- @Override
- public boolean onRestoreData(IntentParams intentParams) {
- data= (String) intentParams.getParam("data");
- return true;
- }
- /**
- * 遷移完成
- */
- @Override
- public void onCompleteContinuation(int i) {}
- }
根據(jù)上面的核心代碼示例,了解實現(xiàn)原理,接下來便可以結(jié)合實際需求完善功能了。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)