当前位置:   article > 正文

HarmongOS音乐播放器开发示例教程_har播放器

har播放器

前言

完整项目代码链接GMusic-HarmongOS-Samples欢迎⭐和fork

对应BiliBili视频鸿蒙开发教程之音乐软件

1. 所需知识和最终效果

屏幕截图

Music Hap
资源获取
权限申请
数据模型
数据读取
UI界面
布局
控件
DirectionalLayout
Text
Button
ListContainer
播放逻辑
List Item点击事件
底部控制栏

2. 资源获取

2.1 权限申请

2.1.1 在config.json文件中的“reqPermissions”字段中声明所需要的权限。

config.json配置

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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, "播放失败");
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

4.2 底部播放控件的设置

在这里用到的PlayManager() 类你可以在链接音乐播放器开发指导
中获取详情

playBtn.setClickedListener(component -> playMusic(component.getContext()));
lastBtn.setClickedListener(component -> lastMusic(component.getContext()));
nextBtn.setClickedListener(component -> nextMusic(component.getContext()));
  • 1
  • 2
  • 3

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());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.2.3 nextMusic()函数

private void lastMusic(Context context){
    currentPlayMusicPos--;
    if (currentPlayMusicPos < 0) {
        currentPlayMusicPos = list.size() - 1;
    }
    MusicBean item = list.get(currentPlayMusicPos);
    play(item,context,0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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, "播放失败");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/328841
推荐阅读
相关标签
  

闽ICP备14008679号