1. 程式人生 > 其它 >Android Studio 學習(三)

Android Studio 學習(三)

技術標籤:android

Android Studio 學習(三)

服務與廣播

學習目標:

1、掌握服務的基本概念,能編寫服務過程並進行呼叫;
2、掌握廣播的基本概念,能實現廣播通訊。
3、需實現的具體功能為:
簡訊到來時自動產生的系統廣播→啟用音樂播放服務程式→活動元件程式使得停止按鈕可用。

專案功能說明:

1、音樂播放介面能顯示歌曲封面、歌曲名、作者、播放進度、當前時間、歌曲總時間
2、能實現上一首、下一首、暫停、播放、停止,並且封面隨之改變
3、拖動進度條可以對應的改變歌曲的播放進度
4、頁面佈局清晰,執行流暢

核心程式碼:

音樂播放頁面由基本資訊介面、控制介面兩個介面組成,分別對應兩個LinearLayout

基本資訊介面包含一個ImageView(歌曲封面)、兩個LinearLayout
基本資訊介面中的第一個LinearLayout中有兩個TextView分別對應歌曲名、作者
基本資訊介面中的第二個LinearLayout中包含兩個TextView和一個SeeBar分別對應當前時間、歌曲總時間、進度條
控制介面包含四個ImageButton分別對應上一首、播放(暫停)、停止、下一首

基本資訊介面:歌曲名、作者

<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="#ffffff"
                android:text="Title"
                android:textSize="20dp" />

            <TextView
                android:id="@+id/author"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#ffffff"
                android:text="Author"
                android:textSize="20dp" />
        </LinearLayout>

基本資訊介面:當前時間、進度條、歌曲總時間

<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/curTime"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:background="#ffffff"
                android:text="00:00" />

            <SeekBar
                android:id="@+id/seekBar"
                android:layout_width="310dp"
                android:layout_height="wrap_content"
                android:background="#ffffff"
                android:scrollbarSize="20sp" />

            <TextView
                android:id="@+id/endTime"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ffffff"
                android:text="00:00" />
        </LinearLayout>

控制介面

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:orientation="horizontal">

        <ImageButton
            android:id="@+id/ptrack"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#ffffff"
            app:srcCompat="@drawable/ptract" />

        <ImageButton
            android:id="@+id/play"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#ffffff"
            app:srcCompat="@drawable/play" />

        <ImageButton
            android:id="@+id/stop"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#ffffff"
            app:srcCompat="@drawable/stop" />

        <ImageButton
            android:id="@+id/ntrack"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#ffffff"
            app:srcCompat="@drawable/ntract" />

</LinearLayout>

事件控制的設計
控制流程:
①點選按鈕 --> ②設定intent,廣播intent並將被MusicService中的MyReceiver 接收到 --> ③根據廣播的intent進行音樂的播放、暫停、切換以及對應進度條的控制 --> ④設定intent,廣播intent並將被MusicboxFragement中的MyReceiver接收到 --> ⑤MusicboxFragement更改播放(暫停)圖示、歌曲封面、歌曲名、作者名
若在歌曲播放的過程中,點選按鈕則執行上述迴圈,否則歌曲播放完成後自動播放下一首並執行上述迴圈(無①點選按鈕)

重要程式碼:
點選事件

public void onClick(View view) {
// 建立 Intent
        Intent intent = new Intent("org.mywechat.action.CTL_ACTION");
        switch (view.getId()) {
            //按下播放/暫停按鈕
            case R.id.play:
                intent.putExtra("control", 1);
                break;
            // 按下 停止 按鈕
            case R.id.stop:
                intent.putExtra("control", 2);
                break;
            // 按下 上一首
            case R.id.ptrack:
                intent.putExtra("control", 3);
                break;
            // 按下 下一首
            case R.id.ntrack:
                intent.putExtra("control", 4);
                break;
        }
        // 傳送廣播,將被Service 元件 中的BroadcastReceiver 接收到
        getActivity().sendBroadcast(intent);
}

MusicFragement中的MyReceiver
public class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // 獲取 Intent 中的update訊息,update 代表播放狀態
            int update = intent.getIntExtra("update", -1);
            // 獲取 Intent 中的current訊息,current代表當前正在播放的歌曲
            int current = intent.getIntExtra("current", -1);
            if (current >= 0) {
                title.setText(titleStrs[current]);
                author.setText(authorStrs[current]);
                imag.setImageResource(imagStrs[current]);
            }
            switch (update) {
                //沒有 播放狀態
                case 0x11:
                    play.setImageResource(R.drawable.play);
                    status = 0x11;
                    title.setText("");
                    author.setText("");
                    imag.setImageResource(R.drawable.music);
                    break;
                //控制系統進入 播放狀態
                case 0x12:
                    //播放狀態下設定使用暫停圖示
                    play.setImageResource(R.drawable.pause);
                    //設定當前狀態
                    status = 0x12;
                    break;
                //控制系統進入暫停狀態
                case 0x13:
                    //暫停狀態下設定使用播放圖示
                    play.setImageResource(R.drawable.play);
                    //設定當前狀態
                    status = 0x13;
                    break;
            }
        }
}

MusicService中的MyReceiver

public void onReceive(Context context, Intent intent) {
            int control = intent.getIntExtra("control", -1);
            switch (control) {
                //播放或暫停
                case 1:
                    //原來處於沒有播放狀態
                    if (status == 0x11) {
                        // 準備 並播放 音樂
                        prepareAndPlay(musics[current]);
                        status = 0x12;
                    }
                    //原來處於播放狀態
                    else if (status == 0x12) {
                        //暫停
                        mediaPlayer.pause();
                        //改為暫停狀態
                        status = 0x13;
                    }
                    // 原來 處於 暫停狀態
                    else if (status == 0x13) {
                        //播放
                        mediaPlayer.start();
                        // 改變狀態
                        status = 0x12;
                    }
                    break;
                //停止 播放
                case 2:
                    //如果原來正在播放或暫停
                    if (status == 0x12 || status == 0x13) {
                        // 停止播放
                        mediaPlayer.pause();
                        mediaPlayer.seekTo(0);
                        status = 0x11;
                    }
                    break;
                // 上一首
                case 3:
                    if (status == 0x12 || status == 0x13) {
                        current = ((current - 1) + musics.length) % musics.length;
                        prepareAndPlay(musics[current]);
                        status = 0x12;
                    }
                    break;
                // 下一首
                case 4:
                    if (status == 0x12 || status == 0x13) {
                        current = (current + 1) % musics.length;
                        prepareAndPlay(musics[current]);
                        status = 0x12;
                    }
                    break;
            }

            // 廣播通知 MusicboxFragment 更改圖示、文字框
            Intent sendIntent = new Intent(MusicboxFragment.UPDATE_ACTION);
            sendIntent.putExtra("update", status);
            sendIntent.putExtra("current", current);
            //傳送廣播,將被MusicboxFragment元件中的BroadcastReceiver接收到
            sendBroadcast(sendIntent);
        }
}

音樂準備和播放

private void prepareAndPlay(String music) {
        int max;
        // 開啟指定音樂檔案
        try {
            AssetFileDescriptor afd = assetManager.openFd(music);
            mediaPlayer.reset();
            // 使用MediaPlayer載入指定的聲音檔案。
            mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            // 準備聲音
            mediaPlayer.prepare();
            max = mediaPlayer.getDuration();
            seekBar.setMax(max);
            endTime.setText(MusicService.formatTime(max));
            //建立一個程序來控制進度條
            handler = new Handler() {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                }
            };//訊息傳遞
            DelayThread delaythread = new DelayThread(100);
            delaythread.start();
            //播放
            mediaPlayer.start();


        } catch (IOException e) {
            e.printStackTrace();
        }

}

MediaPlayer完成事件監聽

 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                //實現自動播放
                current = (current + 1) % musics.length;
                //傳送廣播 通知 MusicboxFragment 更改文字框
                Intent sendIntent = new Intent(MusicboxFragment.UPDATE_ACTION);
                sendIntent.putExtra("current", current);
                // 傳送廣播將被MusicboxFragment元件中的BroadcastReceiver 接收到
                sendBroadcast(sendIntent);
                //準備並播放音樂
                prepareAndPlay(musics[current]);
            }
        });

seekBar監聽

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            //設定當前時間
                curTime.setText(MusicService.formatTime(i));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            //拖動跳轉
                mediaPlayer.seekTo(seekBar.getProgress());
            }
        });

控制seekBar的程序

class DelayThread extends Thread {
        int milliseconds;

        public DelayThread(int i) {
            milliseconds = i;
        }

        public void run() {
            while (true) {
                try {
                    sleep(milliseconds);
                    //設定音樂進度讀取頻率
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                handler.sendEmptyMessage(0);
            }
        }

}

執行截圖:
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

小結

本專案的難點在於Service和Fragement之間相互廣播以及進度條的設定。Service和Fragement之間相互廣播的關鍵是要弄清楚整個專案的事件控制流程(參考事件“控制流程的設計”)。進度條的設定需要使用Handler,以及多程序,使用Handler讓SeekBar獲取歌曲的實時位置,然後在開一個程序handler.sendEmptyMessage(0).

專案原始碼:https://gitee.com/chenranranran/mobile-terminal-development.git