• 实验课—Android开发可以简单播放的音乐播放器


    简易播放器

    本次实验要求实现一个简单的音乐播放器。

    主要实现的功能有:可以实现多首音乐播放(此处音乐放置在Raw下,并非是获取存储中的文件)、实现列表中上一首下一首播放、进度条可以拖动、播放时显示当前歌曲信息。

    功能不难,基本上都是常规代码设计,搞清楚逻辑,写起来就完事儿了。再次特别感谢参考博客:小妖的博客

    1.布局

    2.Adapter设配列表

    3.点击列表,触发监听事件

    4.播放

    5.开始和暂停

    6.上一首、下一首

    7.效果图

    首先是布局:ListVIew、seekBar等,设置背景、以及顶部项目名,没有啥难度。


     接下来是Adapter适配器适配ListVIew。

    首先是先新建一个MusicFile类,将一首音乐的歌曲名、歌手名、专辑封面、总时长、歌曲分类封装起来。

    private String musicName;
    private int imageID;
    private String singer;
    private String sorter;
    private String minutes;
    private int path;

    然后为每个列表项布局music_item.xml

     MusicAdapter.java

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.util.List;
    
    public class MusicAdapter extends ArrayAdapter<MusicFile> {
        private int resourceId;
    
        public MusicAdapter(Context context, int textViewResourceId, List<MusicFile> objects) {
            super(context, textViewResourceId, objects);
            resourceId = textViewResourceId;
    
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            //根据position获取待显示的Name实例
            MusicFile music = getItem(position);
            //获取子视图控件实例
            View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            ImageView imageID = (ImageView) view.findViewById(R.id.imageView);
            TextView musicName = (TextView) view.findViewById(R.id.music_name);
            TextView singer = (TextView) view.findViewById(R.id.singer);
            TextView sorter = (TextView) view.findViewById(R.id.sorter);
            TextView time = (TextView) view.findViewById(R.id.minutes);
            //将Name实例内的名字和头像赋值给子视图控件实例
            imageID.setImageResource(R.drawable.music1);
            musicName.setText(music.getMusicName());
            singer.setText(music.getSinger());
            sorter.setText(music.getSorter());
            time.setText(music.getMinutes());
            return view;
        }
    }

    MainActivity.java中全局变量列表:

        private ListView musiclist;
        private TextView musiclistCurrentTime;
        private TextView musiclistTotalTime;
        private TextView infotextView1;
        private TextView infotextView2;
        private ImageView imageView;
        private ImageView musiclistPlay;
        private SeekBar seekBar;
    
        private MediaPlayer mediaPlayer;
        private Handler handler;
        private Thread thread = new Thread();
        private MusicAdapter adapter;
        private ListView listView;
        private List<MusicFile> MusicList = new ArrayList<>();
    
        private static final int IDLE = 0;   //空闲:没有播放音乐
        private static final int PAUSE = 1;  //暂停:播放音乐时暂停
        private static final int START = 2;  //正在播放音乐
        private boolean flag = false;//控制进度条的索引
    
        private static final int CURR_TIME_VALUE = 1;
    
        private int currState = IDLE;//当前播放器的状态
        private int currPosition;//list的当前选中项的索引值(第一项对应0)

    MainActivity中,适配ListView:

        private MusicAdapter adapter;
        private ListView listView;
        private List<MusicFile> MusicList = new ArrayList<>();
        adapter = new MusicAdapter(MainActivity.this, R.layout.music_item, MusicList);
        listView = (ListView) findViewById(R.id.musiclist);
        listView.setAdapter(adapter);

    初始化数据:

        //初始化列表数据
        private void initInfo() {
            MusicFile nw = new MusicFile("新世界", R.drawable.nwimage, "华晨宇", "5:51", "心愿歌单", R.raw.newworld);
            MusicList.add(nw);
            MusicFile mh = new MusicFile("疯人院", R.drawable.mhimage, "华晨宇", "6:37", "华语精选", R.raw.madhouse);
            MusicList.add(mh);
            MusicFile nc = new MusicFile("Nobody Can Save Me", R.drawable.ncimage, "Linkin Park", "3:45", "摇滚精选", R.raw.ns);
            MusicList.add(nc);
            MusicFile ss = new MusicFile("神树", R.drawable.ssimage, "华晨宇", "5:19", "Love Songs", R.raw.shenshu);
            MusicList.add(ss);
            MusicFile co = new MusicFile("After the After party", R.drawable.aaimage, "Charli XCX", "3:39", "Love Songs", R.raw.aa);
            MusicList.add(co);
            MusicFile aa = new MusicFile("Children of A Miracle", R.drawable.coimage, "Don Diablo", "3:09", "欧美精选", R.raw.co);
            MusicList.add(aa);
    
            MusicFile sp = new MusicFile("杀破狼", R.drawable.spimage, "JS", "4:40", "心愿歌单", R.raw.sp);
            MusicList.add(sp);
            MusicFile yl = new MusicFile("月球", R.drawable.yqimage, "银临", "4:39", "华语精选", R.raw.yl);
            MusicList.add(yl);
            MusicFile nc1 = new MusicFile("Nobody Can Save Me", R.drawable.ncimage, "Linkin Park", "3:45", "摇滚精选", R.raw.ns);
            MusicList.add(nc1);
            MusicFile aa1 = new MusicFile("Children of A Miracle", R.drawable.coimage, "Don Diablo", "3:09", "欧美精选", R.raw.co);
            MusicList.add(aa);
            MusicFile nw2 = new MusicFile("新世界", R.drawable.nwimage, "华晨宇", "5:51", "心愿歌单", R.raw.newworld);
            MusicList.add(nw2);
            MusicFile co1 = new MusicFile("After the After party", R.drawable.aaimage, "Charli XCX", "3:39", "Love Songs", R.raw.aa);
            MusicList.add(co1);
    
    
        }

    到现在为止,UI界面已经初始化好了,接下来就是处理点击列表项,播放音乐。

    //列表点击事件
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
            MusicFile currMf = MusicList.get(position);
            infotextView1.setText(currMf.getMusicName());
            infotextView2.setText(currMf.getSinger());
            //获取专辑图片
            imageView.setImageResource(currMf.getImageID());
            //点击列表项,ImageView的初始状态都为play
            musiclistPlay.setImageDrawable(getResources().getDrawable(R.drawable.pause));
            if (currState == IDLE) {
                //记录当前列表项的下标
                currPosition = position;
                play(position);
            //在播放中的音乐,重置掉    
            } else {
                mediaPlayer.reset();
                //记录下标
                currPosition = position;
                play(position);
            }
        }

    播放函数play:

        //播放
        private void play(int position) {
            //根据当前列表项的下标,获取MusicList中对应的歌曲以及路径
            MusicFile currMf = MusicList.get(position);
            int currPath = currMf.getPath();
            //初始化mediaPlayer
            mediaPlayer = MediaPlayer.create(this, currPath);
            mediaPlayer.start();
            //初始化seekBar
            initSeekBar();
            //设置当前状态为START
            currState = START;
            //开启新线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    flag = true;
                    while (flag) {
                        //实时更新进度条
                        if (mediaPlayer.getCurrentPosition() < seekBar.getMax()) {
                            seekBar.setProgress(mediaPlayer.getCurrentPosition());
                            Message msg = handler.obtainMessage(CURR_TIME_VALUE,
                                    toTime(mediaPlayer.getCurrentPosition()));
                            handler.sendMessage(msg);
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            flag = false;
                        }
                    }
                }
            }).start();
        }

    handler初始化:

            handler = new Handler() {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case CURR_TIME_VALUE:
                            musiclistCurrentTime.setText(msg.obj.toString());
                    }
                }
    
    
            };

    其中initSeekBar()

        //初始化进度条
        private void initSeekBar() {
            //获取总时长
            int duration = mediaPlayer.getDuration();
            seekBar.setMax(duration);
            seekBar.setProgress(0);
            if (duration > 0) {
                musiclistTotalTime.setText(toTime(duration));
            }
        }

    对要显示的时间进行格式化处理,显示“xx:xx”:totime()

        //格式化时间
        private String toTime(int duration) {
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("mm:ss", Locale.getDefault());
            sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));
            date.setTime(duration);
            return sdf.format(date);
        }

     基本点击播放效果也已经完成,接下来就是下方按钮(此处用的是ImageView进行布局,没有本质差别)所产生的对应效果。

    onPlayClick()

        //播放按钮(前提是已经点击列表项)
        public void onPlayClick(View v) {
            switch (currState) {
                case PAUSE:
                    mediaPlayer.start();
                    musiclistPlay.setImageDrawable(getResources().getDrawable(R.drawable.pause));
                    currState = START;
                    break;
                case START:
                    mediaPlayer.pause();
                    musiclistPlay.setImageDrawable(getResources().getDrawable(R.drawable.play));
                    currState = PAUSE;
                    break;
            }
        }

    点击下一首和上一首,原理基本相同,稍微有一点差别就是对于两端音乐上下首的处理。

    上一首:onPreviousClick()

        //上一首
        public void onPreviousClick(View v) {
            previous();
        }
    
        private void previous() {
            if (currPosition > 0) {
                switch (currState) {
                    case IDLE:
                        //滚动列表到下一项
                        musiclist.smoothScrollToPosition(currPosition - 1);
                        //模拟点击Item时间,触发监听器
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(currPosition - 1, null, null),
                                currPosition - 1,
                                musiclist.getItemIdAtPosition(currPosition - 1));
                        break;
                    case START:
                    case PAUSE:
                        stop();
                        musiclist.smoothScrollToPosition(currPosition - 1);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(currPosition - 1, null, null),
                                currPosition - 1,
                                musiclist.getItemIdAtPosition(currPosition - 1));
                        break;
                }
            //如果currPosition等于0,也就是列表第一个
            } else {
                switch (currState) {
                    case IDLE:
                        //则设置滚动到列表尾,也就是最后一个musiclist.getCount() - 1
                        musiclist.smoothScrollToPosition(musiclist.getCount() - 1);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(musiclist.getCount() - 1, null, null),
                                musiclist.getCount() - 1,
                                musiclist.getItemIdAtPosition(musiclist.getCount() - 1));
                        break;
                    case START:
                    case PAUSE:
                        stop();
                        musiclist.smoothScrollToPosition(musiclist.getCount() - 1);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(musiclist.getCount() - 1, null, null),
                                musiclist.getCount() - 1,
                                musiclist.getItemIdAtPosition(musiclist.getCount() - 1));
                        break;
                }
            }
    
        }

    下一首onNextClick():

        //下一首
        public void onNextClick(View v) {
            next();
        }
    
        private void next() {
            if (currPosition != musiclist.getCount()-1) {
                switch (currState) {
                    case IDLE:
                        musiclist.smoothScrollToPosition(currPosition + 1);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(currPosition + 1, null, null),
                                currPosition + 1,
                                musiclist.getItemIdAtPosition(currPosition + 1));
                        break;
                    case START:
                    case PAUSE:
                        stop();
                        musiclist.smoothScrollToPosition(currPosition + 1);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(currPosition + 1, null, null),
                                currPosition + 1,
                                musiclist.getItemIdAtPosition(currPosition + 1));
                        break;
                }
            //如果currPosition等于musiclist.getCount() - 1,也就是列表最后一个
            } else {
                switch (currState) {
                    case IDLE:
                        //那么,设置滚动到列表首,也就是第一首下标为0
                        musiclist.smoothScrollToPosition(0);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(0, null, null),
                                0,
                                musiclist.getItemIdAtPosition(0));
                        break;
                    case START:
                    case PAUSE:
                        stop();
                        musiclist.smoothScrollToPosition(0);
                        musiclist.performItemClick(
                                musiclist.getAdapter().getView(0, null, null),
                                0,
                                musiclist.getItemIdAtPosition(0));
                        break;
                }
            }
        }

    performItemClick源码

        public boolean performItemClick(View view, int position, long id) {
            if (mOnItemClickListener != null) {
                playSoundEffect(SoundEffectConstants.CLICK);
                mOnItemClickListener.onItemClick(this, view, position, id);
                if (view != null) {
                    view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                }
                return true;
            }
     
            return false;
        } 

    点击上一首或者下一首时,如果有其他在播放,终止其mediaPlayer,stop():

        //终止当前播放
        private void stop() {
            initState();
            mediaPlayer.stop();
            currState = IDLE;
        }

    initState():

        //更新界面
        private void initState() {
            musiclistCurrentTime.setText("00:00");
            musiclistTotalTime.setText("00:00");
            flag = false;
            seekBar.setProgress(0);
            musiclistPlay.setImageDrawable(getResources().getDrawable(R.drawable.pause));
        }

    最终效果展示:

    Today And Next
  • 相关阅读:
    Boa移植到Android——ztg
    How to port lighttpd to Android
    android 4.4源码下载——百度云盘地址
    CentOS7——解压7z文件——p7zip
    android—mm—mmm—没有规则可以创建target/product/generic/obj/SHARED_LIBRARIES
    日常美食 小纪
    日常美食 小纪
    上海植物园
    上海之行(一)田子坊
    上海之行(一)田子坊
  • 原文地址:https://www.cnblogs.com/yayyer/p/12708983.html
Copyright © 2020-2023  润新知