HarmonyOS 鸿蒙Next里直播列表丝滑切换进直播间求技术支持

HarmonyOS 鸿蒙Next里直播列表丝滑切换进直播间求技术支持 我现在用的组件是 ‘@ohos/ijkplayer’,我想在直播列表里点详情的时候,丝滑进去直播间,不卡顿,无闪烁,在鸿蒙里能做到吗,我感觉列表的的视频、直播能不能跟详情页里的是同一个页面,但是要怎么做呢,还没有思路,有大佬试过吗 或者有没有能提供一点技术思路,看看有没有合适的技术方案,目前是有一个列表,列表里会有视频、图片、直播,点击视频、直播能进入详情页

import { IjkMediaPlayer } from '[@ohos](/user/ohos)/ijkplayer'
import type {
  OnPreparedListener,
  OnVideoSizeChangedListener,
  OnCompletionListener,
  OnErrorListener
} from '[@ohos](/user/ohos)/ijkplayer'

更多关于HarmonyOS 鸿蒙Next里直播列表丝滑切换进直播间求技术支持的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

开发者您好,对您描述期望实现的效果未能完全理解,提供以下demo(demo为点击跳转播放线上视频,模拟跳转直播页)。如参考以下方案无法解决您的问题,请您提供希望实现的效果图,方便问题分析和解决。

// Index.ets
import { IjkMediaPlayer} from '@ohos/ijkplayer';

class liveRoom {
  id: string = '';
  title: string = '';
  url: string = '';
}

@Entry
@ComponentV2
struct Index {
  pageStack: NavPathStack = new NavPathStack();
  private liveRooms: liveRoom[] = [
    { id: 'r1', title: '电竞直播', url: 'xxx.mp4' }, // 可自行添加视频链接
    { id: 'r2', title: '户外直播', url: 'xxx.mp4' } // 可自行添加视频链接
  ];

  @Builder
  pageMap(name: string, param: ESObject) {
    if (name === 'LivePlayerPage') {
      LivePlayerPage({ videoUrl: param as string })
    }
  }

  build() {
    Navigation(this.pageStack) {
      // 首页内容(直播列表)
      List({ space: 8 }) {
        ForEach(this.liveRooms, (item: liveRoom) => {
          ListItem() {
            Text(item.title)
              .fontSize(18)
              .padding(16)
              .backgroundColor('#f0f0f0')
              .onClick(() => {
                this.pageStack.pushPath({ name: 'LivePlayerPage', param: item.url})
              });
          };
        });
      }
      .width('100%');
    }
    .mode(NavigationMode.Stack)
    .hideTitleBar(true)
    .navDestination(this.pageMap)
  }
}

@ComponentV2
struct LivePlayerPage {
  private mContext: object | undefined = undefined;
  private mIjkMediaPlayer = IjkMediaPlayer.getInstance();
  @Require @Param videoUrl: string = '';

  onPageShow() {
    // 开始播放
    if (this.mContext) {
      this.play(this.videoUrl.toString());
    }
  }

  onPageHide() {
    // 停止播放
    this.mIjkMediaPlayer?.stop();
    this.mIjkMediaPlayer?.release();
  }

  build() {
    NavDestination() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Auto, justifyContent: FlexAlign.Start }) {
        Column() {
          XComponent({
            id: 'xcomponentId',
            type: 'surface',
            libraryname: 'ijkplayer_napi'
          })
            .onLoad((event?: object) => {
              if (!!event) {
                this.initDelayPlay(event);
              }
            })
            .onDestroy(() => {
              this.mIjkMediaPlayer?.stop();
              this.mIjkMediaPlayer?.release();
            })
            .width('100%')
            .aspectRatio(1);
        }.aspectRatio(1);
      };
    }.title('直播间')
  }

  // initDelayPlay
  private initDelayPlay(context: object) {
    this.mContext = context;
    this.play(this.videoUrl.toString());
  }

  private play(url: string) {
    // 设置XComponent回调的context
    if (!!this.mContext) {
      this.mIjkMediaPlayer.setContext(this.mContext, 'xcomponentId');
    }
    // 初始化配置
    this.mIjkMediaPlayer.native_setup();
    // 设置视频源
    this.mIjkMediaPlayer.setDataSource(url);
    // 如果实际场景为打开m3u8视频流且网速较慢,可以开启hls起播优化
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, 'fetch_first', 'on');
    // 预读数据的缓冲区大小
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'max-buffer-size', '1024000');
    // 停止预读的最小帧数
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'min-frames', '100');
    // 启动预加载
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'start-on-prepared', '1');
    // 设置无缓冲,这是播放器的缓冲区,有数据就播放
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'packet-buffering', '0');
    // 跳帧处理,CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'framedrop', '5');
    // 最大缓冲cache是3s
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'max_cached_duration', '3000');
    // 无限制收流
    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'infbuf', '1');
    this.mIjkMediaPlayer.setOptionLong(IjkMediaPlayer.OPT_CATEGORY_PLAYER, 'infbuf', '1');
    // 屏幕常亮
    this.mIjkMediaPlayer.setScreenOnWhilePlaying(true);
    this.mIjkMediaPlayer.setMessageListener();
    this.mIjkMediaPlayer.prepareAsync();
    this.mIjkMediaPlayer.start();
  }
}

更多关于HarmonyOS 鸿蒙Next里直播列表丝滑切换进直播间求技术支持的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next直播列表丝滑切换进直播间

主要涉及ArkUI的List组件性能优化与页面路由管理。可使用LazyForEach懒加载列表项,配合Swiper或Navigation组件实现预加载与平滑过渡。通过PageTransition动画定制转场效果,并利用异步加载与缓存策略减少卡顿。

在HarmonyOS Next中实现直播列表到直播间的丝滑切换,可以通过以下技术方案实现:

核心思路:共享播放器实例

要实现无卡顿、无闪烁的切换,关键在于让列表页和详情页共享同一个播放器实例,而不是销毁重建。

具体实现方案:

1. 使用全局状态管理

通过AppStorage或自定义全局管理器保存播放器实例:

// 全局播放器管理器
export class PlayerManager {
  private static instance: IjkMediaPlayer | null = null;
  
  static getPlayer(): IjkMediaPlayer {
    if (!this.instance) {
      this.instance = new IjkMediaPlayer();
    }
    return this.instance;
  }
  
  static release() {
    this.instance?.release();
    this.instance = null;
  }
}

2. 页面间传递播放器状态

在列表页点击时,不立即跳转,而是先准备播放器:

// 列表页
async onItemClick(item: LiveItem) {
  const player = PlayerManager.getPlayer();
  await player.setDataSource(item.url);
  await player.prepareAsync();
  
  // 跳转到详情页
  router.pushUrl({
    url: 'pages/DetailPage',
    params: { isPrepared: true }
  });
}

3. 详情页无缝衔接

详情页直接使用已准备的播放器:

// 详情页
aboutToAppear() {
  const player = PlayerManager.getPlayer();
  if (this.isPrepared) {
    // 直接开始播放,无需重新准备
    player.start();
  }
  
  // 将播放器绑定到当前页面的Surface
  this.surfaceId = ...;
  player.setDisplay(this.surfaceId);
}

4. 使用页面转场动画

配置平滑的页面转场效果:

router.pushUrl({
  url: 'pages/DetailPage',
  params: { /* ... */ }
}, router.RouterMode.Standard, (err) => {
  if (!err) {
    // 可以在这里添加自定义转场动画
  }
});

5. 优化Surface切换

确保Surface切换时视频渲染不间断:

  • 在跳转前保持最后一帧渲染
  • 使用setDisplay(null)临时解绑,到新页面再重新绑定
  • 考虑使用Texture组件作为渲染容器

6. 内存管理注意事项

  • 在应用退出时统一释放播放器
  • 页面返回时暂停播放但不释放
  • 监听页面生命周期,适时暂停/恢复播放

这种方案能够实现真正的丝滑切换,因为播放器实例和视频解码状态都得到了保持,只有渲染表面发生了切换,避免了重新初始化和缓冲带来的卡顿。

回到顶部