HarmonyOS鸿蒙Next音乐播放器开发示例教程

HarmonyOS鸿蒙Next音乐播放器开发示例教程 完整项目源代码
github仓库代码 欢迎⭐和fork

所需知识和最终结果

2. 资源获取
2.1 权限申请
2.1.1 在config.json文件中的reqPermissions字段中声明所需要的权限。

2.1.2 在Ability中动态申请

  1. 申请对应权限
@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setMainRoute(MainAbilitySlice.class.getName());
    if (verifySelfPermission("ohos.permission.READ_MEDIA") != IBundleManager.PERMISSION_GRANTED) {
        if (canRequestPermission("ohos.permission.READ_MEDIA")) {
            // 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示)
            requestPermissionsFromUser(
                new String[] { "ohos.permission.READ_MEDIA" }, MY_PERMISSIONS_REQUEST_RW);
        } else {
            new ToastDialog(this).setText("需要授予应用读取存储权限").setAlignment(LayoutAlignment.CENTER).show();
        }
    }
}
  1. 检测申请结果
@Override
public void onRequestPermissionsFromUserResult (int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == MY_PERMISSIONS_REQUEST_RW) {// 匹配requestPermissions的requestCode
        if (grantResults.length > 0
            && grantResults[0] == IBundleManager.PERMISSION_GRANTED) {
            new ToastDialog(this).setText("所有权限已经被授予").setAlignment(LayoutAlignment.CENTER).show();
        } else {
            new ToastDialog(this).setText("所有权限已经被拒绝").setAlignment(LayoutAlignment.CENTER).show();
        }
    }
}

2.2 数据模型
声明对应的音乐对象

public class MusicBean {
    private int id;
    private String title;
    private String song;
    private String data;
    private String duration;
    private String artist;
    private String album;

    public MusicBean() {}

    /**
     * @param id music_id
     * @param title music_name
     * @param song
     * @param data music_path
     * @param duration music_duration
     * @param artist music_artist
     */
    public MusicBean(int id, String title, String song, String data, String duration, String artist, String album) {
        this.id = id;
        this.title = title;
        this.song = song;
        this.data = data;
        this.duration = duration;
        this.artist = artist;
        this.album = album;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSong() {
        return song;
    }

    public void setSong(String song) {
        this.song = song;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getDuration() {
        return duration;
    }

    public void setDuration(String duration) {
        this.duration = duration;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public String getAlbum() {
        return album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }
}

2.3 数据读取
2.3.1 通过外部存储的Uri来获取对应的ResultSet

/**
 * @param context Context
 * @return
 * If you want to get information about AVStorage.Audio.Media, please refer to:
 * https://developer.harmonyos.com/cn/docs/documentation/doc-references/avstorage_audio_media-0000001054678942
 * If you want to get information about this function, please refer to:
 * https://developer.harmonyos.com/cn/docs/documentation/doc-guides/tv-media-playback-0000001050714866
 */
private ResultSet queryAvStore(Context context) {
    ResultSet resultSet = null;
    DataAbilityHelper helper = DataAbilityHelper.creator(context);
    try {
        resultSet = helper.query(AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI, null, null);
    } catch (DataAbilityRemoteException e) {
        e.printStackTrace();
    }
    return resultSet;
}

2.3.2 通过ResultSet获取对应的音频对象
关于 artistalbum 字段的获取可以参考文章 HarmongOS音频开发之音频信息获取(以获取艺术家为例)

/**
 * @param context Context
 * @return
 * get playlist
 * If you want to get information about AVStorage.AVBaseColumns.ID or others, please refer to:
 * https://developer.harmonyos.com/cn/docs/documentation/doc-references/avstorage_avbasecolumns-0000001054358919#ZH-CN_TOPIC_0000001054358919__DATA
 */
private List<MusicBean> getMusicBeanList(Context context) {
    ResultSet resultSet = queryAvStore(context);
    List<MusicBean> musicBeans = new ArrayList<>();
    while (resultSet.goToNextRow()) {
        MusicBean musicBean = new MusicBean();
        musicBean.setId(resultSet.getInt(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.ID)));
        musicBean.setData(resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA)));
        musicBean.setTitle(resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.TITLE)));
        musicBean.setDuration(new SimpleDateFormat("mm:ss").format(new Date(resultSet.getLong(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DURATION)))));
        musicBean.setSong(resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DISPLAY_NAME)));
        musicBean.setArtist(resultSet.getString(resultSet.getColumnIndexForName("artist")));
        musicBean.setAlbum(resultSet.getString(resultSet.getColumnIndexForName("album")));
        musicBeans.add(musicBean);
    }
    return musicBeans;
}

3. UI布局
3.1 主页面布局
主页面布局主要采用了 DirectionalLayout 布局,如果你想获取对应的布局信息,可以参考链接 DirectionalLayout布局,以下是 ability_main.xml 布局

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:orientation="vertical">
    <ListContainer
        ohos:id="$+id:music_bean_lc"
        ohos:height="0vp"
        ohos:width="match_parent"
        ohos:orientation="vertical"
        ohos:weight="1"
        ohos:background_element="$media:background"/>
    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:background_element="#E6000000"
        ohos:orientation="horizontal"
        ohos:padding="5vp">
        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="0vp"
            ohos:weight="1"
            ohos:orientation="vertical"
            ohos:layout_alignment="vertical_center">
            <Text
                ohos:id="$+id:bottom_music_name_tv"
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:text="$string:music_name"
                ohos:text_size="20fp"
                ohos:text_color="$color:color_white"/>
            <Text
                ohos:id="$+id:bottom_music_artists_tv"
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:text="$string:music_artist"
                ohos:text_size="10fp"
                ohos:text_color="$color:color_white"/>
        </DirectionalLayout>
        <Button
            ohos:id="$+id:bottom_last_btn"
            ohos:height="50vp"
            ohos:width="50vp"
            ohos:margin="10vp"
            ohos:background_element="$graphic:ic_last"/>
        <Button
            ohos:id="$+id:bottom_play_btn"
            ohos:height="50vp"
            ohos:width="50vp"
            ohos:margin="10vp"
            ohos:background_element="$graphic:ic_play"/>
        <Button
            ohos:id="$+id:bottom_next_btn"
            ohos:height="50vp"
            ohos:width="50vp"
            ohos:margin="10vp"
            ohos:background_element="$graphic:ic_next"/>
    </DirectionalLayout>
</DirectionalLayout>

3.2 音乐布局

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:padding="10vp"
    ohos:orientation="horizontal">
    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="0vp"
        ohos:weight="3"
        ohos:orientation="vertical">
        <Text
            ohos:id="$+id:music_name_tv"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="$string:music_name"
            ohos:text_size="20fp"
            ohos:text_color="$color:color_white"/>
        <Text
            ohos:id="$+id:music_artists_tv"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="$string:music_artist"
            ohos:text_size="10fp"
            ohos:text_color="$color:color_white"/>
    </DirectionalLayout>
    <Text
        ohos:id="$+id:music_duration_tv"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="$string:music_duration"
        ohos:text_size="10fp"
        ohos:layout_alignment="right|bottom"
        ohos:text_color="$color:color_white"/>
</DirectionalLayout>

4. 播放逻辑
4.1 列表点击事件的设置

listContainer.setItemClickedListener((listContainer1, component, i, l) -> {
    //get music object
    MusicBean item = (MusicBean) listContainer1.getItemProvider().getItem(i);
    //update some information
    currentPlayMusicPos = i;
    musicNameTv.setText(item.getTitle());
    musicArtistTv.setText(item.getArtist()+"-"+item.getAlbum());
    //update the button image
    //Regarding this execution statement, I hope you refer to the link below
    //https://blog.csdn.net/weixin_43699716/article/details/117448709?spm=1001.2014.3001.5501
    playBtn.setBackground(new VectorElement(this, ResourceTable.Graphic_ic_pause));
    //play the music
    try {
        if (PlayManager.getInstance().play(new Source(DataAbilityHelper
            .creator(component.getContext())
            .openFile(Uri.appendEncodedPathToUri(AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(item.getId())), "r")), 0)) {
            HiLog.info(hiLogLabel, "播放成功");
        } else {
            HiLog.info(hiLogLabel, "播放失败");
        }
    } catch (DataAbilityRemoteException | FileNotFoundException e) {
        e.printStackTrace();
        HiLog.info(hiLogLabel, "播放失败");
    }
});

4.2 底部播放控件的设置
在这里用到的 PlayManager 类你可以在链接 音乐播放器开发指导 中获取详情

playBtn.setClickedListener(component -> playMusic(component.getContext()));
lastBtn.setClickedListener(component -> lastMusic(component.getContext()));
nextBtn.setClickedListener(component -> nextMusic(component.getContext()));

4.2.1 playMusic()函数

private void playMusic(Context context) {
    if(currentPlayMusicPos == -1) {
        new ToastDialog(context).setText("请从播放列表中选择歌曲").setAlignment(LayoutAlignment.CENTER).show();
    } else {
        if(PlayManager.getInstance().isPlaying()) {
            PlayManager.getInstance().pause();
            playBtn.setBackground(new VectorElement(this, ResourceTable.Graphic_ic_play));
        } else {
            MusicBean item = list.get(currentPlayMusicPos);
            play(item, context, PlayManager.getInstance().getAudioCurrentPosition());
        }
    }
}

4.2.2 lastMusic()函数

private void lastMusic(Context context) {
    currentPlayMusicPos--;
    if (currentPlayMusicPos < 0) {
        currentPlayMusicPos = list.size() - 1;
    }
    MusicBean item = list.get(currentPlayMusicPos);
    play(item, context, 0);
}

4.2.3 nextMusic()函数

private void nextMusic(Context context) {
    currentPlayMusicPos++;
    if (currentPlayMusicPos >= list.size()) {
        currentPlayMusicPos = 0;
    }
    MusicBean item = list.get(currentPlayMusicPos);
    play(item, context, 0);
}

4.2.4 play()函数

private void play(MusicBean musicBean, Context context, int time) {
    musicNameTv.setText(musicBean.getTitle());
    musicArtistTv.setText(musicBean.getArtist()+"-"+musicBean.getAlbum());
    try {
        if (PlayManager.getInstance().play(new Source(DataAbilityHelper
            .creator(context)
            .openFile(Uri.appendEncodedPathToUri(AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(musicBean.getId())), "r")), time)) {
            HiLog.info(hiLogLabel, "播放成功");
            playBtn.setBackground(new VectorElement(this, ResourceTable.Graphic_ic_pause));
        } else {
            HiLog.info(hiLogLabel, "播放失败");
        }
    } catch (DataAbilityRemoteException | FileNotFoundException e) {
        e.printStackTrace();
        HiLog.info(hiLogLabel, "播放失败");
    }
}

更多关于HarmonyOS鸿蒙Next音乐播放器开发示例教程的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next音乐播放器开发示例教程的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中开发音乐播放器,首先需创建项目并配置权限,如ohos.permission.READ_MEDIA。使用AudioPlayer类实现播放功能,通过prepare()play()pause()等方法控制播放状态。UI设计可使用ListContainer展示音乐列表,Slider控制音量与进度。数据管理通过DataAbilityHelper访问本地或云端音乐文件。最后,确保应用适配不同设备,优化性能与用户体验。

回到顶部