實驗課—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));
    }

 

最終效果展示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM