14-3 RN之保存播放过的音频数据到 Realm 数据库

67 阅读2分钟

在这一节中,我们将学习如何将播放音频、上一首、下一首和暂停音频时的状态保存到 Realm 数据库。

1. 保存音频播放数据

fetchShow 中,我们首先从 API 获取音频数据,并从 dvastate 中提取当前播放的音频信息(如 idtitlethumbnailUrlcurrentTime 等),然后保存到 Realm 数据库中。

*fetchShow(payload, {call, put, select}) {
    const {data} = yield call(axios.get, REQUEST_URL);
    // 获取当前播放器的状态
    const {id, title, thumbnailUrl, currentTime}: PlayerModelState = yield select(({player}: RootState) => player);
    saveProgram({id, title, thumbnailUrl, currentTime, duration: getDuration()});
},

2. 暂停时更新播放进度

在暂停时,我们需要更新当前播放的时间:

*pause(_, {put, select}) {
    const {id, currentTime}: PlayerModelState = yield select(({player}: RootState) => player);
    saveProgram({id, currentTime});
},

3. 上一首、下一首

由于上一首和下一首的功能会触发 fetchShow,因此无需再次单独添加保存方法,fetchShow 已经处理了这些情况。

4. 减少代码重复

如上所示,保存播放数据的逻辑已经非常简洁。正是因为在之前的章节中,我们已经很好的封装了业务逻辑。如果没有 dva 的话,这些逻辑会直接放在页面中,导致代码混乱,增加后期修改的难度。

尽量将 业务逻辑UI 逻辑 分离,这样在后期的开发过程中能大大减少修改和维护的工作量。

5. 处理 IProgram 类型

在定义 saveProgram 函数时,参数类型为 any,这虽然可以工作,但不推荐。为了更好地利用 TypeScript 的类型检查,我们将其改为 IProgram 类型。

export function saveProgram(data: IProgram) {
  try {
    realm.write(() => {
      realm.create('Program', data, true); // true 表示若 id 存在则更新
    });
  } catch (e) {
    console.log('保存失败');
  }
}

但是我们遇到了一个问题:IProgram 中的属性默认是必填的,而我们更新时只传入了 idcurrentTime,因此会报错。为了解决这个问题,我们可以将 IProgram 的属性改为可选项:

export interface IProgram {
  id: string;
  title?: string;
  thumbnailUrl?: string;
  currentTime?: number;
  duration?: number;
}

6. 使用 Partial 类型

更优雅的做法是使用 TypeScript 的 Partial 类型,它会自动将所有属性设置为可选:

export function saveProgram(data: Partial<IProgram>) {
  try {
    realm.write(() => {
      realm.create('Program', data, true);
    });
  } catch (e) {
    console.log('保存失败');
  }
}

Partial 类型可以让我们只传入需要更新的属性,避免了手动修改类型的麻烦。

7. 总结

在这一节中,我们通过 dvaselectsaveProgram 方法,将音频播放的状态持久化到 Realm 数据库中。我们还使用了 TypeScript 的高级类型 Partial 来简化代码,使得在保存数据时只传入必要的字段。

下一节,我们将继续实现音频播放记录的显示功能。