1. 程式人生 > >開發一個簡易音樂播放器

開發一個簡易音樂播放器

本人初學Android,最近做了一個實現安卓簡單音樂播放功能的播放器,收穫不少,於是便記錄下來自己的思路與知識總結,重溫自己的探索之路。

1  那麼先上幾張截圖來看下程式實現效果吧



2 可以看出基本實現的功能有

暫停(播放),上(下)一首,停止播放

點選列表中歌曲進行播放,點選按鈕以彈出歌曲列表

螢幕上顯示歌曲名稱,演唱者,專輯圖片

顯示播放進度條,拖拽進度條以控制播放

通知欄中顯示相關資訊,並可在通知欄上控制播放

3 總體開發思路


一共有兩個Activity介面(分別是主介面和播放細節介面),一個用以在後臺播放音樂的Service,一個可以和使用者進行互動Notificatication。 為了能夠使得活動與活動,活動與服務,活動與通知之間通訊,採取傳送廣播的做法,由於我在MainActivity,PlayActivity,MusicService中都獲取了歌曲資訊列表,所以在他們之間直接傳遞歌曲下標location和狀態isPlaying即可

核心是由MainActivity通過startService方法控制Service來進行播放

  • MainActivity中點選事件發生後更新自己的UI,同時startService
  • PlayActivity中點選事件發生後更新自己UI,傳送廣播給MainActivity,讓MainActivity更新UI,startService,從而實現PlayActivity間接控制播放
  • Notification點選事件發生後發生廣播給MainActivity,讓MainActivity更新UI,startService,從而實現Notification間接控制播放

4 重要功能實現

1  內容提供器 ContentProvider 
  • 內容提供器用法一般有兩種: 使用現有的內容提供器和建立自己的內容提供器。
  • 在使用系統自帶的內容提供器,注意要在AndroidManifest中新增許可權宣告,如果是危險許可權,還要進行執行時許可權宣告,這裡由於本人手機低於Android6.0系統,顧沒有進行執行時申請。
這裡我們使用了安卓自帶媒體庫所提供的介面來訪問資料。詳情看2 2  安卓MediaStore 安卓為我們提供了自帶的媒體庫,我們可以直接從中訪問到所需的資料。這個MediaStore包括了多媒體資料庫的所有資訊,包括音訊,視訊和影象,android把所有的多媒體資料庫介面進行了封裝,所有的資料庫不用自己進行建立,直接呼叫利用ContentResolver去掉用那些封裝好的介面就可以進行資料庫的操作了,例項如下:
1 通過genContentResolver的查詢方法獲得儲存有資料的Cursor物件 //query方法第一個引數為 Uri:這個Uri代表要查詢的資料庫名稱加上表的名稱,這裡我們獲取所有的歌曲資訊,後面四個引數為查詢條件和資料排列條件,這裡我們都使用null
      
Cursor cursor=context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null)
2   獲得了資料結果Cursor物件後,我們讀取資料到程式的思路是:通過移動游標的位置來遍歷cursor的 每一行,然後根據所需提取每一行相應列的資訊,並新增到程式的變數中
for(int i=0;i<cursor.getCount();i++){
            cursor.moveToNext();
            Mp3Info mp3Info=new Mp3Info();
            mp3Info.setUrl(cursor.getString(cursor .getColumnIndex(MediaStore.Audio.Media.DATA)));
            mp3InfoList.add(mp3Info);
3  介面程式設計
  • 1 SeekBar的實現注意宣告android:thumb="@drawable/media_player_progress_button"//滑動的游標
  • 2 按鈕ImageButton背景宣告我採用如下:app:srcCompat="@drawable/play"/>
  •         這樣在活動中便可通過button.setDateResource(R.drawable....)來實現背景的切換,如果介面程式設計中直接使用setBackground方法,到時候會造成按鈕背景的重疊而          不是切 換的效果(親測)
  • 3 使用ListIView的時候注意要在活動中setAdapter(),並設定響應子項點選事件(通過開啟服務來播放點選的那首音樂)
5 Activity 1 點選專輯圖片時使用startActivity方法由MainActivity進入PlayActivity,並由intent傳遞相關資訊
Intent intent=new Intent(MainActivity.this,PlayActivity.class);
                intent.putExtra("state",isPlaying);
                intent.putExtra("location",location);
                startActivity(intent);

2 使用startService方法開啟服務,通過intent傳遞相關資訊(case 0:播放所傳遞的location下標那首歌 case 1 :暫停/播放     case 2:seekBar拖動播放     case 3: 停止播放)
//傳遞歌曲下標location並啟動服務
        Intent intent=new Intent(MainActivity.this,MusicService.class);
        intent.putExtra("tag",0);
        intent.putExtra("location",location);
        startService(intent);
6  實現後臺自動播放下一首音樂 :只需為MediaPlayer物件設定setOnCompletionListener()方法即可,在方法中使歌曲下標+1,播放即可,自動播放下一首後記得傳送廣播給 活動和Notification以更新UI
 //設定自動播放下一首
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                if(mediaPlayer!=null){
                    try {
                        if (++location < mp3InfoList.size()) {
                            mediaPlayer.reset();
                            mediaPlayer.setDataSource(MusicService.this, Uri.parse(mp3InfoList.get(location).getUrl()));
                            mediaPlayer.prepare();
                            mediaPlayer.start();
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
7 實現顯示播放進度功能:在Service中建立一個繼承於AsyncTask的類,在該類子執行緒中執行緒每0.5秒傳送一次帶有當前播放進度的broadcast給活動介面以更新UI
 public Integer doInBackground(Void...parms){
//設定while (true)以達到迴圈不斷的目的
 while (true){
            try{
                Thread.sleep(500);//執行緒沉睡500毫秒
            }
            catch (Exception e){
                e.printStackTrace();
            }
            position=mediaPlayer.getCurrentPosition();//獲得mediaPlayer當前播放進度
            if(position<mediaPlayer.getDuration()){
                Intent mIntent=new Intent("com.example.musicplayer.update_seekbar");
                mIntent.putExtra("position",position);
                sendBroadcast(mIntent);//傳送廣播
            }else{
                break;
            }
        }
            return 0;
        }
8
  • 為SeekBar設定點選拖動事件,通知seetOnSeekBarChangeListener(...)方法,其中OnSeekBarChangeListener類物件需重寫三個方法,在 public void onStop TrackingTouch(SeekBar seekBar)方法中傳送廣播給Service(帶有Progress資訊)
  • 在Service中接收progress資訊呼叫MediaPlayer.seekTo(progress)方法來響應拖動事件
//為SeekBar設定點選拖動事件
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress=seekBar.getProgress();
                Intent intent=new Intent(MainActivity.this, MusicService.class);
                intent.putExtra("tag",2);
                intent.putExtra("progress",progress);
                startService(intent);
            }
        });

使用帶有佈局的通知 : 與使用普通通知無異,但給通知使用setContent(RemoteViews remoteViews)方法來設定佈局,remoteViews的點選事件的響應為向MainActivity傳送廣播
remoteViews = new RemoteViews(getPackageName(), R.layout.remoteviews_item_dl);//設定RemoteViews的佈局
            remoteViews.setTextViewText(R.id.tv_filename, getPackageName());   // 設定標題
            remoteViews.setTextViewText(R.id.tv_content, "this is notification");   // 設定內容
            remoteViews.setImageViewBitmap(R.id.notification_imageView,bitmap);//設定控制元件Bitmap
          // 設定點選事件響應結果為傳送廣播
            remoteViews.setOnClickPendingIntent(R.id.notification_next,PendingIntent.getBroadcast(this,0,
            new Intent("com.example.musicplayer.notification.next").putExtra("tag2",2), PendingIntent.FLAG_UPDATE_CURRENT));
            Notification notification=new NotificationCompat.builder(this).setContent(remotoViews).build();//構建出帶有特定佈局的通知  
            manager.notify(0,notification);//顯示通知


10 實現點選按鈕彈出AlertIDialog,在dialog中顯示歌曲列表listView並設定點選事件,關鍵在於為ListView控制元件設定介面卡:這裡使用SimpleAdapter建立(要求繫結的資料是List<HashMap<String, Object>>資料型別(String為key,第二個引數為對應資料))獲得dialog框架佈局LinearoutLayout和歌曲列表佈局ListView,並將ListIView新增到框架佈局上
  •  建立一個數組儲存listview上顯示的資料 
  • 獲取到集合資料 
  • 建立SimpleAdapter例項,引數解讀(context,資料陣列,listVIew item的佈局,key陣列,佈局id陣列),將key儲存的資料賦予佈局中相應id控制元件
  • 為listView設定Adapter
  • dialog.setView(dialog 框架佈局),dialog.show()
  • listView設定點選事件(傳送帶有點選item下標資訊的廣播給MainActivity)
    //通過AlertDialog顯示歌曲列表
    public void showMusicList(){
        Log.d("PlayActivity","showMusicList start");
        LinearLayout linearLayoutMain = new LinearLayout(this);//自定義一個佈局檔案
        linearLayoutMain.setLayoutParams(new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        Log.d("PlayActivity","LinearLayout created");
        ListView listView = new ListView(this);//this為獲取當前的上下文
        listView.setFadingEdgeLength(0);
        List<Map<String,String>>musicList=new ArrayList<Map<String, String>>();
        for(int i=0;i<mp3InfoList.size();i++){
            Map<String,String>item=new HashMap<String,String>();
            item.put("musicName",mp3InfoList.get(i).getTitle().toString());
            item.put("artist",mp3InfoList.get(i).getArtist().toString());
            musicList.add(item);
        }
        Log.d("PlayActivity","LinearLayout created and itialized");
         //
        SimpleAdapter adapter=new SimpleAdapter(PlayActivity.this,musicList,R.layout.music_item
                ,new String[]{"musicName","artist"}
                , new int[]{R.id.music_item_musicName,R.id.music_item_artist});
        Log.d("PlayActivity","SimpleAdapter created");
        listView.setAdapter(adapter);
        linearLayoutMain.addView(listView);
        Log.d("PlayActivity","listView was added to the linearLayout");
        final AlertDialog dialog=new AlertDialog.Builder(this).setTitle("歌曲列表").setView(linearLayoutMain)
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // TODO Auto-generated method stub
                        dialog.cancel();
                    }
                }).create();
        Log.d("PlayActivity","Dialog created");
        dialog.show();
        Log.d("PlayActivity","Dialog showed");
        //響應子項點選事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
         //           注意這裡的引數第三個引數Item在介面卡中的位置
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                //更新自身UI
                musicNameView.setText(mp3InfoList.get(i).getTitle());
                artistView.setText(mp3InfoList.get(i).getArtist());
                durationView.setText(MediaUtil.formatTime(mp3InfoList.get(i).getDuration()));
                //傳送廣播附帶歌曲下標給MainActivity來控制服務播放歌曲
                Intent intent=new Intent("com.example.musicplayer.react_to_playactiity");
                intent.putExtra("tag1",4);
                intent.putExtra("location",i);
                sendBroadcast(intent);
                Log.d("PlayActivity","broadcast sended");
                dialog.cancel();
                Log.d("PlayActivity","Dialog canceled");
            }
        });
    }

5 開發思路的實現細節

1 首先新建儲存mp3音樂相關屬性資訊的實體類Mp3Info(儲存url,title,artist等等)

ublic class Mp3Info {
    private String url;//路徑
    private String title;//歌曲名
    private String artist;//藝術家
    private long duration;//歌曲時長
    private long id;
    private long albumId;//以上兩種Id用以獲取專輯圖片
    public Mp3Info(){

    }
    public Mp3Info(String url,String title,String artist,long duration,long id,long albumId){
        this.url=url;
        this.title=title;
        this.artist=artist;
        this.duration=duration;
        this.id=id;
        this.albumId=albumId;
    }
    public void setUrl(String url){
        this.url=url;
    }
    public void setTitle(String title){
        this.title=title;
    }
    public void setArtist(String artist){
        this.artist=artist;
    }
    public void setDuration(long duration){
        this.duration=duration;
    }
    public void setId(long id){this.id=id;}
    public void setAlbumId(long albumId){this.albumId=albumId;}
    public String getUrl(){
        return url;
    }
    public String getTitle(){
        return title;
    }
    public String getArtist(){
        return artist;
    }
    public long getDuration(){
        return duration;}

 public long getId() {
        return id;
    }

    public long getAlbumId() {
        return albumId;
    }
}
2 新建MediaUtil類用於從安卓媒體庫中獲取歌曲資訊並儲存在程式的List中,提供靜態方法給其他程式碼來直接複用
public class MediaUtil {
    //獲取專輯封面的Uri
    private static final Uri albumArtUri = Uri.parse("content://media/external/audio/albumart");
   //從安卓媒體庫中獲取歌曲資訊並儲存在程式的List中,並提供靜態方法給其他類來直接獲得生成的歌曲列表資訊
    public static List<Mp3Info>getMp3InfoList(Context context){
        Cursor cursor=context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
               null);
        List<Mp3Info>mp3InfoList=new ArrayList<>();
        for(int i=0;i<cursor.getCount();i++){
            cursor.moveToNext();
            Mp3Info mp3Info=new Mp3Info();
            mp3Info.setUrl(cursor.getString(cursor
                    .getColumnIndex(MediaStore.Audio.Media.DATA)));
            mp3Info.setTitle(cursor.getString(cursor
                    .getColumnIndex(MediaStore.Audio.Media.TITLE)));
            mp3Info.setArtist(cursor.getString(cursor
                    .getColumnIndex(MediaStore.Audio.Media.ARTIST)));
            mp3Info.setDuration(cursor.getLong(cursor
                    .getColumnIndex(MediaStore.Audio.Media.DURATION)));
            mp3Info.setId(cursor.getLong(cursor
                    .getColumnIndex(MediaStore.Audio.Media._ID)));
            mp3Info.setAlbumId(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)));
             mp3InfoList.add(mp3Info);

        }
        return mp3InfoList;
    }
    /**
     * 格式化時間,將毫秒轉換為分:秒格式//將long型別轉化為String型,
     * @param time
     * @return
     */
    public static String formatTime(long time) {
        String min = time / (1000 * 60) + "";
        String sec = time % (1000 * 60) + "";
        if (min.length() < 2) {
            min = "0" + time / (1000 * 60) + "";
        } else {
            min = time / (1000 * 60) + "";
        }
        if (sec.length() == 4) {
            sec = "0" + (time % (1000 * 60)) + "";
        } else if (sec.length() == 3) {
            sec = "00" + (time % (1000 * 60)) + "";
        } else if (sec.length() == 2) {
            sec = "000" + (time % (1000 * 60)) + "";
        } else if (sec.length() == 1) {
            sec = "0000" + (time % (1000 * 60)) + "";
        }
        return min + ":" + sec.trim().substring(0, 2);
    }
    /**
     * 獲取預設專輯圖片
     * @param context
     * @return
     */
    public static Bitmap getDefaultArtwork(Context context,boolean small) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        if(small){	//返回小圖片
            return BitmapFactory.decodeStream(context.getResources().openRawResource(R.drawable.music5), null, opts);
        }
        return BitmapFactory.decodeStream(context.getResources().openRawResource(R.drawable.defaultalbum), null, opts);
    }


    /**
     * 從檔案當中獲取專輯封面點陣圖
     * @param context
     * @param songid
     * @param albumid
     * @return
     */
    private static Bitmap getArtworkFromFile(Context context, long songid, long albumid){
        Bitmap bm = null;
        if(albumid < 0 && songid < 0) {
            throw new IllegalArgumentException("Must specify an album or a song id");
        }
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            FileDescriptor fd = null;
            if(albumid < 0){
                Uri uri = Uri.parse("content://media/external/audio/media/"
                        + songid + "/albumart");
                ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
                if(pfd != null) {
                    fd = pfd.getFileDescriptor();
                }
            } else {
                Uri uri = ContentUris.withAppendedId(albumArtUri, albumid);
                ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
                if(pfd != null) {
                    fd = pfd.getFileDescriptor();
                }
            }
            options.inSampleSize = 1;
            // 只進行大小判斷
            options.inJustDecodeBounds = true;
            // 呼叫此方法得到options得到圖片大小
            BitmapFactory.decodeFileDescriptor(fd, null, options);
            // 我們的目標是在800pixel的畫面上顯示
            // 所以需要呼叫computeSampleSize得到圖片縮放的比例
            options.inSampleSize = 100;
            // 我們得到了縮放的比例,現在開始正式讀入Bitmap資料
            options.inJustDecodeBounds = false;
            options.inDither = false;
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;

            //根據options引數,減少所需要的記憶體
            bm = BitmapFactory.decodeFileDescriptor(fd, null, options);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return bm;
    }

    /**
     * 獲取專輯封面點陣圖物件
     * @param context
     * @param song_id
     * @param album_id
     * @param allowdefalut
     * @return
     */
    public static Bitmap getArtwork(Context context, long song_id, long album_id, boolean allowdefalut, boolean small){
        if(album_id < 0) {
            if(song_id < 0) {
                Bitmap bm = getArtworkFromFile(context, song_id, -1);
                if(bm != null) {
                    return bm;
                }
            }
            if(allowdefalut) {
                return getDefaultArtwork(context, small);
            }
            return null;
        }
        ContentResolver res = context.getContentResolver();
        Uri uri = ContentUris.withAppendedId(albumArtUri, album_id);
        if(uri != null) {
            InputStream in = null;
            try {
                in = res.openInputStream(uri);
                BitmapFactory.Options options = new BitmapFactory.Options();
                //先制定原始大小
                options.inSampleSize = 1;
                //只進行大小判斷
                options.inJustDecodeBounds = true;
                //呼叫此方法得到options得到圖片的大小
                BitmapFactory.decodeStream(in, null, options);
                /** 我們的目標是在你N pixel的畫面上顯示。 所以需要呼叫computeSampleSize得到圖片縮放的比例 **/
                /** 這裡的target為800是根據預設專輯圖片大小決定的,800只是測試數字但是試驗後發現完美的結合 **/
                if(small){
                    options.inSampleSize = computeSampleSize(options, 40);
                } else{
                    options.inSampleSize = computeSampleSize(options, 600);
                }
                // 我們得到了縮放比例,現在開始正式讀入Bitmap資料
                options.inJustDecodeBounds = false;
                options.inDither = false;
                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                in = res.openInputStream(uri);
                return BitmapFactory.decodeStream(in, null, options);
            } catch (FileNotFoundException e) {
                Bitmap bm = getArtworkFromFile(context, song_id, album_id);
                if(bm != null) {
                    if(bm.getConfig() == null) {
                        bm = bm.copy(Bitmap.Config.RGB_565, false);
                        if(bm == null && allowdefalut) {
                            return getDefaultArtwork(context, small);
                        }
                    }
                } else if(allowdefalut) {
                    bm = getDefaultArtwork(context, small);
                }
                return bm;
            } finally {
                try {
                    if(in != null) {
                        in.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    /**
     * 對圖片進行合適的縮放
     * @param options
     * @param target
     * @return
     */
    public static int computeSampleSize(BitmapFactory.Options options, int target) {
        int w = options.outWidth;
        int h = options.outHeight;
        int candidateW = w / target;
        int candidateH = h / target;
        int candidate = Math.max(candidateW, candidateH);
        if(candidate == 0) {
            return 1;
        }
        if(candidate > 1) {
            if((w > target) && (w / candidate) < target) {
                candidate -= 1;
            }
        }
        if(candidate > 1) {
            if((h > target) && (h / candidate) < target) {
                candidate -= 1;
            }
        }
        return candidate;
    }


}
3 活動介面程式設計,這裡直接上程式碼

主介面:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mainActivity_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.Toolbar
        android:id="@+id/mainActivity_toolBar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/mainActivity_toolBar"
    android:background="#FFF">
    <ListView
        android:id="@+id/musicName_list"
        android:layout_width="match_parent"
        android:layout_height="440dp"
        android:textColor="#FFF"/>
     <RelativeLayout
         android:id="@+id/mainActivity_seekBarLayout"
         android:layout_width="match_parent"
         android:layout_height="35dp"
         android:layout_below="@+id/musicName_list"
         android:layout_alignParentLeft="true"
         android:layout_alignParentStart="true"
         android:background="@drawable/drawable_bg">
         <SeekBar
             android:id="@+id/mainActivity_seekBar"
             android:layout_width="match_parent"
             android:layout_height="20dp"
             android:thumb="@drawable/media_player_progress_button"
             />

         <TextView
             android:id="@+id/main_current_position"
             android:layout_width="wrap_content"
             android:layout_height="25dp"
             android:layout_below="@id/mainActivity_seekBar"
             android:text="0:00"
             android:textColor="#060606"/>

         <TextView
             android:id="@+id/main_final_position"
             android:layout_width="wrap_content"
             android:layout_height="25dp"
             android:layout_alignParentRight="true"
             android:layout_below="@id/mainActivity_seekBar"
             android:text="3:00"
             android:textColor="#090808"/>

     </RelativeLayout>
   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_alignParentBottom="true"
       android:background="#7e7677"
       android:layout_below="@+id/mainActivity_seekBarLayout">
       <ImageView
           android:id="@+id/album_view"
           android:layout_width="80dp"
           android:layout_height="match_parent"
           />
       <TextView
           android:id="@+id/mainActivity_musicName"
           android:layout_width="80dp"
           android:layout_toRightOf="@+id/album_view"
           android:layout_marginLeft="5dp"
           android:layout_height="wrap_content"
           android:text="歌曲名稱"
           android:textColor="#090909"/>
       <TextView
           android:id="@+id/mainActivity_artist"
           android:layout_width="80dp"
           android:layout_height="wrap_content"
           android:layout_below="@+id/mainActivity_musicName"
           android:layout_marginLeft="5dp"
           android:layout_toRightOf="@+id/album_view"
           android:text="歌曲作者"
           android:textColor="#060606"/>
       <ImageButton
           android:id="@+id/mainActivity_play_pause"
           android:layout_width="50dp"
           android:layout_height="60dp"
           android:layout_centerInParent="true"
           android:layout_toLeftOf="@+id/mainActivity_next"
           app:srcCompat="@drawable/play"/>
       <ImageButton
           android:id="@+id/mainActivity_next"
           android:layout_width="50dp"
           android:layout_height="60dp"
           android:layout_centerInParent="true"
          app:srcCompat="@drawable/next"
           android:layout_toLeftOf="@+id/mainActivity_menu"/>
       <ImageButton
           android:id="@+id/mainActivity_menu"
           android:layout_width="50dp"
           android:layout_height="60dp"
           android:layout_centerInParent="true"
           android:layout_alignParentRight="true"
           app:srcCompat="@drawable/menu"
           />
   </RelativeLayout>


</RelativeLayout>
</RelativeLayout>
    <android.support.design.widget.NavigationView
        android:id="@+id/mainActivity_nav_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"
        >
    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>
播放細節介面
<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#885959"
    >
    <RelativeLayout
        android:id="@+id/play_activity_toolBar1"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        >
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/playActivity_return"
                android:layout_width="45dp"
                android:layout_height="30dp"
                android:background="@drawable/back_return_normal"/>
            <TextView
                android:id="@+id/playActivity_musicName"
                android:layout_width="match_parent"
                android:layout_height="20dp"
                android:layout_toRightOf="@+id/playActivity_return"
                android:text="歌曲名稱"
                android:layout_marginLeft="5dp"
                android:textColor="#fcfcfc"/>
            <TextView
                android:id="@+id/playActivity_artist"
                android:layout_width="match_parent"
                android:layout_marginLeft="5dp"
                android:layout_height="20dp"
                android:layout_toRightOf="@+id/playActivity_return"
                android:layout_below="@+id/playActivity_musicName"
                android:text="演唱者"
                android:textColor="#c3b9b9"
                />
    </RelativeLayout>
    <ScrollView
        android:id="@+id/playActivity_musicLyrics"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/playActivity_seekbarLayout">

    </ScrollView>


    <RelativeLayout
        android:id="@+id/playActivity_seekbarLayout"
        android:layout_width="match_parent"
        android:layout_height="35dp"
        android:background="@drawable/drawable_bg"
        android:layout_above="@+id/playActivity_toolBar2">

        <SeekBar
            android:id="@+id/playActivity_seekBar"
            android:layout_width="match_parent"
            android:layout_height="20dp"

            android:thumb="@drawable/media_player_progress_button"
            />

        <TextView
            android:id="@+id/current_position"
            android:layout_width="wrap_content"
            android:layout_height="25dp"
            android:layout_below="@id/playActivity_seekBar"
            android:text="0:00"
            android:textColor="#FFF"/>

        <TextView
            android:id="@+id/final_position"
            android:layout_width="wrap_content"
            android:layout_height="25dp"
            android:layout_alignParentRight="true"
            android:layout_below="@id/playActivity_seekBar"
            android:text="3:00"
            android:textColor="#FFF"/>
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/playActivity_toolBar2"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">
        <ImageButton
            android:id="@+id/stop"
            android:layout_width="50dp"
            android:layout_margin="10dp"
            android:layout_height="match_parent"
            app:srcCompat="@drawable/stop"/>
        <ImageButton
            android:id="@+id/previous"
            android:layout_width="50dp"
            android:layout_margin="10dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/stop"
            app:srcCompat="@drawable/previous"/>
        <ImageButton
            android:id="@+id/play_pause"
            android:layout_margin="10dp"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/previous"
            app:srcCompat="@drawable/play"

             />
        <ImageButton
            android:id="@+id/next_music"
            android:layout_width="50dp"
            android:layout_margin="10dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/play_pause"
            app:srcCompat="@drawable/next"
            />
        <ImageButton
            android:id="@+id/music_menu"
            android:layout_width="50dp"
            android:layout_margin="10dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/next_music"
            app:srcCompat="@drawable/playqueue"
            />

    </RelativeLayout>




</RelativeLayout>
4 MainActivity程式設計
public class MainActivity extends AppCompatActivity {
    static ListView listView;
    List<Mp3Info>mp3InfoList;
    Mp3Info mp3Info;
    static int location=0;
    static Boolean isPlaying=false;
    List musicNameList=new ArrayList<>();
    static TextView musicNameView;
    static TextView artistView;
    static ImageView albumView;
    static ImageButton playOrPauseButton;
    static ImageButton nextButton;
    static SeekBar seekBar;
    static TextView currentTiemView;
    static TextView durationView;
    DrawerLayout drawerLayout;
    String Tag="MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          //ToolBar及DrawerLayout
        Toolbar toolbar=(Toolbar)findViewById(R.id.mainActivity_toolBar);
        setSupportActionBar(toolbar);
        ActionBar actionBar=getSupportActionBar();
        if(actionBar!=null){
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeAsUpIndicator(R.drawable.menu);
        }
        drawerLayout=(DrawerLayout)findViewById(R.id.mainActivity_drawer_layout);
          //獲得各個控制元件並設定點選事件
        musicNameView=(TextView)findViewById(R.id.mainActivity_musicName);
        artistView=(TextView)findViewById(R.id.mainActivity_artist);
        playOrPauseButton=(ImageButton)findViewById(R.id.mainActivity_play_pause);
        nextButton=(ImageButton)findViewById(R.id.mainActivity_next);
        seekBar=(SeekBar)findViewById(R.id.mainActivity_seekBar);
        currentTiemView=(TextView)findViewById(R.id.main_current_position) ;
        durationView=(TextView)findViewById(R.id.main_final_position);
        albumView=(ImageView)findViewById(R.id.album_view);
          //設定各控制元件初始檢視為上次離開時所播放的歌曲,如果程序已被Kill掉,則為第一首
        mp3InfoList=MediaUtil.getMp3InfoList(MainActivity.this);
        mp3Info=mp3InfoList.get(location);
        musicNameView.setText(mp3Info.getTitle());
        artistView.setText(mp3Info.getArtist());
        long id=mp3Info.getId();
        long albumId=mp3Info.getAlbumId();
        albumView.setImageBitmap(MediaUtil.getArtwork(this, id,
                albumId, true, false));
        if(isPlaying)
            playOrPauseButton.setImageResource(R.drawable.pause);
        else playOrPauseButton.setImageResource(R.drawable.play);
           //專輯圖片點選事件,進入PlayActivity中,並通過Intent傳遞location和isPlaying狀態
        albumView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent(MainActivity.this,PlayActivity.class);
                intent.putExtra("state",isPlaying);
                intent.putExtra("location",location);
                startActivity(intent);
            }
        });
         //暫停、播放按鈕點選事件
        playOrPauseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                playOrpause();
            }
        });
         //下一首點選事件
        nextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                nextMusic();
            }
        });
        //從媒體庫中獲得音樂列表並顯示到ListView中,同時設定點選事件
        listView=(ListView)findViewById(R.id.musicName_list) ;
        for(int i=0;i<mp3InfoList.size();i++)
            musicNameList.add(mp3InfoList.get(i).getTitle());
        ArrayAdapter aa=new ArrayAdapter(this,android.R.layout.simple_list_item_1,musicNameList);
        listView.setAdapter(aa);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
           @Override
           public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
               location=i;
               setPlay(location);
           }

        });
         //註冊監聽SeekBar變化的監聽器
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.example.musicplayer.update_seekbar");
        UpdateSeekbarBroadcast receiver=new UpdateSeekbarBroadcast();
        registerReceiver(receiver,filter);
         //監聽PlayActivity的點選事件
        IntentFilter filter1=new IntentFilter();
        filter1.addAction("com.example.musicplayer.react_to_playactiity");
        PlayActivityBroadcast receiver1=new PlayActivityBroadcast();
        registerReceiver(receiver1,filter1);
         //註冊監聽Notification的監聽器
        IntentFilter filter2=new IntentFilter();
        filter2.addAction("com.example.musicplayer.notification.previous");
        filter2.addAction("com.example.musicplayer.notification.play_pause");
        filter2.addAction("com.example.musicplayer.notification.next");
        NotificationBroadcast receiver2=new NotificationBroadcast();
        registerReceiver(receiver2,filter2);
         //註冊監聽後臺順序播放的監聽器
        IntentFilter filter3=new IntentFilter();
        filter3.addAction("com.example.musicplayer.order_play");
        OrderPlayBroadcast receiver3=new OrderPlayBroadcast();
        registerReceiver(receiver3,filter3);
         //為SeekBar設定點選拖動事件
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress=seekBar.getProgress();
                Intent intent=new Intent(MainActivity.this, MusicService.class);
                intent.putExtra("tag",2);
                intent.putExtra("progress",progress);
                startService(intent);
            }
        });




    }
    public boolean onCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.toolbar,menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem){
        switch (menuItem.getItemId()){
            case android.R.id.home:drawerLayout.openDrawer(GravityCompat.START);
                break;
            case R.id.search:
                Toast.makeText(MainActivity.this,"You clicked the search button",Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }

    //設定播放某一首歌曲
    public void setPlay(int location){
        //切換播放狀態
        isPlaying=true;
        //根據要播放的音樂曲目更新MainActivity的UI
        mp3Info=mp3InfoList.get(location);
        long id=mp3Info.getId();
        long albumId=mp3Info.getAlbumId();
        musicNameView.setText(mp3Info.getTitle());
        artistView.setText(mp3Info.getArtist());
        Bitmap bitmap = MediaUtil.getArtwork(this, id,
                albumId, true, false);// 獲取專輯點陣圖物件,為大圖
        albumView.setImageBitmap(bitmap);
        //切換播放狀態圖示
            playOrPauseButton.setImageResource(R.drawable.pause);

        seekBar.setMax((int)mp3Info.getDuration());
        currentTiemView.setText("0:00");
        durationView.setText(MediaUtil.formatTime(mp3Info.getDuration()));
        //傳遞歌曲下標location並啟動服務
        Intent intent=new Intent(MainActivity.this,MusicService.class);
        intent.putExtra("tag",0);
        intent.putExtra("location",location);
        startService(intent);


    }
    //播放下一首歌曲
    public void nextMusic(){
        if((++location)<mp3InfoList.size()){
            setPlay(location);
        }
    }
    //播放上一首歌曲
    public void previousMusic(){
        if ((--location)>=0){
            setPlay(location);
        }
    }
    //暫停或繼續播放
    public void playOrpause(){
        Intent intent=new Intent(MainActivity.this,MusicService.class);
        //切換播放狀態並改變狀態圖示
        isPlaying=!isPlaying;
        if(isPlaying)
            playOrPauseButton.setImageResource(R.drawable.pause);
        else playOrPauseButton.setImageResource(R.drawable.play);
        intent.putExtra("tag",1);
        intent.putExtra("state",isPlaying);
        startService(intent);

    }
    //停止播放此首音樂,並將進度條滑至開始處
    public void stopMusic(){
        Intent intent=new Intent(MainActivity.this,MusicService.class);
        intent.putExtra("tag",3);
        if(isPlaying)
            playOrPauseButton.setImageResource(R.drawable.play);
        else playOrPauseButton.setImageResource(R.drawable.pause);
        startService(intent);

    }
    //監聽來自Service的SeekBar變化
    class UpdateSeekbarBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            int position=intent.getIntExtra("position",0);
            currentTiemView.setText(MediaUtil.formatTime(position));
            seekBar.setProgress(position);

        }
    }
    //接收來自PlayActivity的廣播
    class PlayActivityBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            int tag1=intent.getIntExtra("tag1",-1);
            switch (tag1){
                case 0: {
                    playOrpause();
                }
                    break;
                case 1:previousMusic();
                    break;
                case 2:nextMusic();
                    break;
                case 3:stopMusic();
                    default:
                        break;
                case 4:{
                    location=intent.getIntExtra("location",5);
                    setPlay(location);
                }
            }


        }
    }
    //接收來自Notification的廣播
    class NotificationBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            int tag2=intent.getIntExtra("tag2",-1);
            LogUtil.d(Tag,"received the broadcast from notification");
            switch (tag2){
                case 0:previousMusic();
                    break;
                case 1:{
                    playOrpause();
                    isPlaying=intent.getBooleanExtra("state",false);
                }
                    break;
                case 2:nextMusic();
                    break;
                default:
                    break;
            }
        }
    }
    //接收來自後臺自動播放的廣播以更新UI
    class OrderPlayBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            LogUtil.d(Tag,"update ui according to the orderly play");
            location=intent.getIntExtra("location",-1);
            mp3Info=mp3InfoList.get(location);
            long id=mp3Info.getId();
            long albumId=mp3Info.getAlbumId();
            musicNameView.setText(mp3Info.getTitle());
            artistView.setText(mp3Info.getArtist());
            Bitmap bitmap = MediaUtil.getArtwork(MainActivity.this, id,
                    albumId, true, false);// 獲取專輯點陣圖物件,為大圖
            albumView.setImageBitmap(bitmap);
            seekBar.setMax((int)mp3Info.getDuration());
            currentTiemView.setText("0:00");
            durationView.setText(MediaUtil.formatTime(mp3Info.getDuration()));

        }
    }

}

PlayActivity
public class PlayActivity extends AppCompatActivity implements View.OnClickListener {
    TextView musicNameView,artistView;
    Button returnBack;
    ImageButton stop,previousMusic,playOrPauseButton,nextMusic,musicList;
    SeekBar seekBar;
    TextView currentTimeView,durationView;
    Intent intent;
    static int location=0;
    static Boolean isPlaying=false;
    Mp3Info mp3Info;
    List<Mp3Info>mp3InfoList=new ArrayList<>();
    String[]musicNameList;
    String Tag="PlayActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play);
        //獲得歌曲列表資訊
        mp3InfoList=MediaUtil.getMp3InfoList(PlayActivity.this);
        //獲得各控制元件例項
        musicNameView=(TextView)findViewById(R.id.playActivity_musicName) ;
        artistView=(TextView)findViewById(R.id.playActivity_artist);
        stop=(ImageButton)findViewById(R.id.stop);
        previousMusic=(ImageButton)findViewById(R.id.previous);
        playOrPauseButton=(ImageButton)findViewById(R.id.play_pause);
        nextMusic=(ImageButton)findViewById(R.id.next_music);
        musicList=(ImageButton)findViewById(R.id.music_menu);
        returnBack=(Button)findViewById(R.id.playActivity_return);
        seekBar=(SeekBar)findViewById(R.id.playActivity_seekBar);
        currentTimeView=(TextView)findViewById(R.id.current_position);
        durationView=(TextView)findViewById(R.id.final_position);
        //從MainActivity中傳遞過來的資料
        Intent intent1=getIntent();
        location=intent1.getIntExtra("location",0);
        isPlaying=intent1.getBooleanExtra("state",false);
        //根據傳遞過來的資料更新UI檢視
        seekBar.setMax((int)(mp3InfoList.get(location).getDuration()));
        currentTimeView.setText("0:00");
        durationView.setText(MediaUtil.formatTime(mp3InfoList.get(location).getDuration()));
        musicNameView.setText(mp3InfoList.get(location).getTitle());
        artistView.setText(mp3InfoList.get(location).getArtist());
        durationView.setText(MediaUtil.formatTime(mp3InfoList.get(location).getDuration()));
        if(isPlaying)
            playOrPauseButton.setImageResource(R.drawable.pause);
        else playOrPauseButton.setImageResource(R.drawable.play);
        //註冊seekBar監聽器
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.example.musicplayer.update_seekbar");
        UpdateSeekbarBroadcast receiver=new UpdateSeekbarBroadcast();
        registerReceiver(receiver,filter);
        //註冊後臺順序播放的監聽器
        IntentFilter filter1=new IntentFilter();
        filter1.addAction("com.example.musicplayer.order_play");
        OrderPlayBroadcast receiver1=new OrderPlayBroadcast();
        registerReceiver(receiver1,filter1);
        //為SeekBar設定點選拖動事件
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress=seekBar.getProgress();
                Intent intent=new Intent(PlayActivity.this, MusicService.class);
                intent.putExtra("tag",2);
                intent.putExtra("progress",progress);
                startService(intent);
            }
        });
        //設定各按鈕點選事件
        stop.setOnClickListener(this);
        previousMusic.setOnClickListener(this);
        playOrPauseButton.setOnClickListener(this);
        nextMusic.setOnClickListener(this);
        musicList.setOnClickListener(this);
    }
    //監聽來自Service的SeekBar變化
    class UpdateSeekbarBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            int position=intent.getIntExtra("position",0);
            currentTimeView.setText(MediaUtil.formatTime(position));
            seekBar.setProgress(position);

        }
    }
    //接收來自後臺自動播放的廣播以更新UI
    class OrderPlayBroadcast extends BroadcastReceiver{
        @Override
        public void onReceive(Context context,Intent intent){
            LogUtil.d(Tag,"PlayActivity receive broadcast from service orderly play to update UI ");
            location=intent.getIntExtra("location",-1);
            mp3Info=mp3InfoList.get(location);
            musicNameView.setText(mp3Info.getTitle());
            artistView.setText(mp3Info.getArtist());
            seekBar.setMax((int)mp3Info.getDuration());
            currentTimeView.setText("0:00");
            durationView.setText(MediaUtil.formatTime(mp3Info.getDuration()));
        }
    }
    @Override
    public void onClick(View view){
        Intent intent=new Intent("com.example.musicplayer.react_to_playactiity");
        switch (view.getId()){
            case R.id.stop :{
                intent.putExtra("tag1",3);
            }
                break;
            case R.id.previous: {
                isPlaying=!isPlaying;
                previousMusic();
                intent.putExtra("tag1", 1);
            }
                break;
            case R.id.play_pause:{
                isPlaying=!isPlaying;
                if(isPlaying) {
                    playOrPauseButton.setImageResource(R.drawable.pause);
                }
                else {
                    playOrPauseButton.setImageResource(R.drawable.play);
                }
                intent.putExtra("tag1",0);
                intent.putExtra("state",isPlaying);

            }
                break;
            case R.id.next_music:{
                nextMusic();
                intent.putExtra("tag1",2);
            }
                break;
            case R.id.music_menu:
                Log.d("PlayActivity","press the button music_menu");
                 showMusicList();
                break;
            default:
                break;

        }
        sendBroadcast(intent);
    }
    //根據點選事件更新UI檢視
    public void previousMusic(){
        if((--location)>=0)
        {
            seekBar.setMax((int)(mp3InfoList.get(location).getDuration()));
            currentTimeView.setText("0:00");
            durationView.setText(MediaUtil.formatTime(mp3InfoList.get(location).getDuration()));
            musicNameView.setText(mp3InfoList.get(location).getTitle());
            artistView.setText(mp3InfoList.get(location).getArtist());
            playOrPauseButton.setImageResource(R.drawable.pause);
        }
    }
    public void nextMusic(){
        if((++location)>=0)
        {
            seekBar.setMax((int)(mp3InfoList.get(location).getDuration()));
            currentTimeView.setText("0:00");
            durationView.setText(MediaUtil.formatTime(mp3InfoList.get(location).getDuration()));
            musicNameView.setText(mp3InfoList.get(location).getTitle());
            artistView.setText(mp3InfoList.get(location).getArtist());
            playOrPauseButton.setImageResource(R.drawable.pause);
        }
    }
    //通過AlertDialog顯示歌曲列表
    public void showMusicList(){
        Log.d("PlayActivity","showMusicList start");
        LinearLayout linearLayoutMain = new LinearLayout(this);//自定義一個佈局檔案
        linearLayoutMain.setLayoutParams(new LinearLayoutCompat.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        Log.d("PlayActivity","LinearLayout created");
        ListView listView = new ListView(this);//this為獲取當前的上下文
        listView.setFadingEdgeLength(0);
        List<Map<String,String>>musicList=new ArrayList<Map<String, String>>();
        for(int i=0;i<mp3InfoList.size();i++){
            Map<String,String>item=new HashMap<String,String>();
            item.put("musicName",mp3InfoList.get(i).getTitle().toString());
            item.put("artist",mp3InfoList.get(i).getArtist().toString());
            musicList.add(item);
        }
        Log.d("PlayActivity","LinearLayout created and itialized");

        SimpleAdapter adapter=new SimpleAdapter(PlayActivity.this,musicList,R.layout.music_item
                ,new String[]{"musicName","artist"}
                , new int[]{R.id.music_item_musicName,R.id.music_item_artist});
        Log.d("PlayActivity","SimpleAdapter created");
        listView.setAdapter(adapter);
        linearLayoutMain.addView(listView);
        Log.d("PlayActivity","listView was added to the linearLayout");
        final AlertDialog dialog=new AlertDialog.Builder(this).setTitle("歌曲列表").setView(linearLayoutMain)
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // TODO Auto-generated method stub
                        dialog.cancel();
                    }
                }).create();
        Log.d("PlayActivity","Dialog created");
        dialog.show();
        Log.d("PlayActivity","Dialog showed");
        //響應子項點選事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                //更新自身UI
                musicNameView.setText(mp3InfoList.get(i).getTitle());
                artistView.setText(mp3InfoList.get(i).getArtist());
                durationView.setText(MediaUtil.formatTime(mp3InfoList.get(i).getDuration()));
                //傳送廣播附帶歌曲下標給MainActivity來控制服務播放歌曲
                Intent intent=new Intent("com.example.musicplayer.react_to_playactiity");
                intent.putExtra("tag1",4);
                intent.putExtra("location",i);
                sendBroadcast(intent);
                Log.d("PlayActivity","broadcast sended");
                dialog.cancel();
                Log.d("PlayActivity","Dialog canceled");
            }
        });
    }

}

5  MusicService 建立服務類
public class MusicService extends Service {
    List<Mp3Info> mp3InfoList = new ArrayList<>();
    MediaPlayer mediaPlayer;
    Mp3Info mp3Info;
    Notification notification;
    static int location;
    int position;
    static Boolean isPlaying=false;
    RemoteViews contecntViews;
    public MusicService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer=new MediaPlayer();
        //獲得歌曲Mp3Info類列表
        mp3InfoList = MediaUtil.getMp3InfoList(MusicService.this);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d("MusicService", "service onStartommand");
        int tag= intent.getIntExtra("tag", -1);
        switch (tag) {
            case 0: {
                isPlaying=true;
                location=intent.getIntExtra("location",-1);
                mp3Info=mp3InfoList.get(location);
                String url = mp3Info.getUrl();
                String title=mp3Info.getTitle();
                String artist=mp3Info.getArtist();
                long id=mp3Info.getId();
                long albumId=mp3Info.getAlbumId();
                try {
                    if (mediaPlayer != null) {
                        mediaPlayer.reset();
                    }
                    mediaPlayer.setDataSource(this, Uri.parse(url));
                    mediaPlayer.prepare();
                    mediaPlayer.start();
                    showNotification(title,artist,id,albumId);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }break;
            case 1:{
                    if(mediaPlayer!=null) {
                        if (mediaPlayer.isPlaying()) {
                            mediaPlayer.pause();
                        } else mediaPlayer.start();
                    }
                    isPlaying=intent.getBooleanExtra("state",false);
                if(isPlaying==true)
                   isPlaying=false;
                else
                   isPlaying=true;

            }break;
            case 2:{
                isPlaying=true;
                int progress=intent.getIntExtra("progress",0);
                if(mediaPlayer!=null){
                    mediaPlayer.seekTo(progress);
                }
            }break;
            case 3:{
                mediaPlayer.stop();
                try{
                    mediaPlayer.prepare();
                    mediaPlayer.seekTo(0);}
                catch (Exception e){
                    e.printStackTrace();
                }
            } break;
        }
        //
         new PlayProgress().execute();
        //設定自動播放下一首
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                if(mediaPlayer!=null){
                    try {
                        if (++location < mp3InfoList.size()) {
                            mediaPlayer.reset();
                            mediaPlayer.setDataSource(MusicService.this, Uri.parse(mp3InfoList.get(location).getUrl()));
                            mediaPlayer.prepare();
                            mediaPlayer.start();
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
                //通過傳送廣播讓MainActivity,PlayActivity更新UI
                Intent intent=new Intent("com.example.musicplayer.order_play");
                intent.putExtra("location",location);
                sendBroadcast(intent);
                //後臺更新NotificationUI
                isPlaying=true;
                mp3Info=mp3InfoList.get(location);
                String title=mp3Info.getTitle();
                String artist=mp3Info.getArtist();
                long id=mp3Info.getId();
                long albumId=mp3Info.getAlbumId();
                showNotification(title,artist,id,albumId);
            }
        });
        return super.onStartCommand(intent, flags, startId);
    }
    public class PlayProgress extends AsyncTask<Void,Integer,Integer>{
        @Override
        public void onPreExecute(){