安卓实训项目:基于储存卡音乐播放器实训报告5.0
安卓實訓項目:基于儲存卡音樂播放器實訓報告5.0
(一)功能要求
在基于存儲卡音樂播放器V0.4基礎上,作如下修改:
1、創建應用程序常量接口保存廣播頻道常量
2、在音樂播放器應用程序類里添加兩個屬性
– currentMusicIndex
– currentPosition
– 訪問它們的方法
3、創建MusicPlayService來完成音樂的播放、暫停以及切換工作
4、利用廣播來實現MainActivity與MusicPlayService之間的通信
(二)運行效果
(三)涉及知識點
1.標簽(TextView)
2.按鈕(Button)
3.媒體播放器(MediaPlayer)
4.進度條(ProgressBar)
5.線程(Thread)
6.消息處理器(Handler)
7.列表視圖(ListView)
8.異步任務(AsyncTask)
9.應用程序(Application)
10.服務(Service)
11.廣播接收者(BroadcastReceiver)
(四)實現步驟
1.創建安卓應用【SDCardMusicPlayerV0.5】
2、將圖片素材拷貝到drawable目錄與mipmap目錄
3、播放按鈕背景圖片選擇器 - play_button_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/play_button_pressed" android:state_pressed="true"/><item android:drawable="@drawable/play_button" android:state_pressed="false"/> </selector>4、暫停按鈕背景圖片選擇器 - pause_button_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/pause_button_pressed" android:state_pressed="true" /><item android:drawable="@drawable/pause_button" android:state_pressed="false" /> </selector>該處使用的url網絡請求的數據。
5、上一首按鈕背景圖片選擇器 - previous_button_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/previous_button_pressed" android:state_pressed="true" /><item android:drawable="@drawable/previous_button" android:state_pressed="false" /> </selector>6、下一首按鈕背景圖片選擇器 - next_button_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/next_button_pressed" android:state_pressed="true" /><item android:drawable="@drawable/next_button" android:state_pressed="false" /> </selector>7、文件里授權訪問外置存儲卡,設置應用程序圖標
8、主布局資源文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background"android:orientation="vertical"android:padding="20dp"tools:context=".ui.MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><ProgressBarandroid:id="@+id/pbScanMusic"android:layout_width="100dp"android:layout_height="100dp"android:visibility="gone" /><TextViewandroid:id="@+id/tvScanMusic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/scan_music"android:textColor="#0000ff"android:textSize="25sp"android:visibility="gone" /></LinearLayout><ListViewandroid:id="@+id/lvMusicName"android:layout_width="match_parent"android:layout_height="0dp"android:layout_marginBottom="16dp"android:layout_weight="8" /><TextViewandroid:id="@+id/tvMusicName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="0.5"android:textColor="#0000ff"android:textSize="20sp" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginBottom="10dp"android:layout_weight="0.5"android:gravity="center"android:orientation="horizontal"><TextViewandroid:id="@+id/tvCurrentPosition"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="#ff0000" /><ProgressBarandroid:id="@+id/pbMusicProgress"style="?android:attr/progressBarStyleHorizontal"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="6" /><TextViewandroid:id="@+id/tvDuration"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="#ff00ff" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="0.5"android:gravity="center"android:orientation="horizontal"><Buttonandroid:id="@+id/btnPrevious"android:layout_width="60dp"android:layout_height="50dp"android:background="@drawable/previous_button_selector"android:onClick="doPrevious" /><Buttonandroid:id="@+id/btnPlayOrPause"android:layout_width="60dp"android:layout_height="50dp"android:background="@drawable/play_button_selector"android:onClick="doPlayOrPause" /><Buttonandroid:id="@+id/btnNext"android:layout_width="60dp"android:layout_height="50dp"android:background="@drawable/next_button_selector"android:onClick="doNext" /></LinearLayout> </LinearLayout>9、字符串資源文件strings.xml
<resources><string name="app_name">基于存儲卡音樂播放器V0.5</string><string name="scan_music">掃描外置存儲卡上全部MP3音樂,請耐心等待……</string> </resources>10、創建音樂名列表項模板music_name_list_item.xml
11、創建ui子包,將MainActivity拖進ui子包
12、創建entity子包,在里面創建音樂實體類 - Music
13、創建app子包,在里面創建音樂播放器應用程序類 - MusicPlayerApplication
14、在項目清單文件里給音樂播放器應用程序類注冊
15、創建adapter子包,在里面創建音樂適配器 - MusicAdapter
16、在app子包常見應用程序常量接口 - AppConstants
17、創建service子包,在里面創建音樂播放服務類 - MusicPlayService
package com.example.musicplayerv05.Service;import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.MediaPlayer; import android.os.IBinder;import androidx.annotation.Nullable;import com.example.musicplayerv05.R; import com.example.musicplayerv05.app.AppConstants; import com.example.musicplayerv05.app.MusicPlayerApplication; import com.example.musicplayerv05.entity.Music;import java.io.IOException; import java.util.List;public class MusicPlayService extends Service implements AppConstants {private MediaPlayer mp; // 媒體播放器private String musicName; // 音樂文件名private Thread thread; // 線程private boolean isRunning; // 線程循環控制變量private List<Music> musicList;//音樂數據源private MusicPlayerApplication app;//音樂播放器應用程序private MusicReceiver receiver;//廣播接收者@Overridepublic void onCreate() {super.onCreate();//獲取音樂播放器對象app = (MusicPlayerApplication) getApplication();//獲取音樂列表musicList = app.getMusicList();//創建媒體播放器mp = new MediaPlayer();//給媒體播放器注冊完成監聽器mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mediaPlayer) {//切換下一曲nextMusic();}});//設置循環變量為真isRunning = true;//創建子線程,定時發送消息thread = new Thread(() -> {while (isRunning) {if (mp.isPlaying()) {//創建意圖Intent intent = new Intent();//設置廣播頻道intent.setAction(INTENT_ACTION_UPDATE_PROGRESS);//設置當前播放位置app.setCurrentPosition(mp.getCurrentPosition());//讓意圖攜帶播放時長數據intent.putExtra(DURATION, mp.getDuration());//暫停圖標intent.putExtra(CONTROL_ICON, R.drawable.pause_button_selector);//發送廣播sendBroadcast(intent);try {//線程休眠500毫秒Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}});//啟動更新進度的線程thread.start();//創建音樂廣播接收器receiver = new MusicReceiver();//創建意圖過濾器IntentFilter filter = new IntentFilter();//通過意圖過濾器添加廣播頻道filter.addAction(INTENT_ACTION_PLAY_OR_PAUSE);filter.addAction(INTENT_ACTION_PLAY);filter.addAction(INTENT_ACTION_PREVIOUS);filter.addAction(INTENT_ACTION_NEXT);//注冊廣播接收者registerReceiver(receiver, filter);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {//獲取播放音樂名musicName = musicList.get(app.getCurrentMusicIndex()).getMusicName();try {//設置播放源mp.setDataSource(musicName);//緩沖播放源mp.prepare();//播放位置歸零app.setCurrentPosition(0);//創建意圖Intent intent1 = new Intent();//更新進度intent1.setAction(INTENT_ACTION_UPDATE_PROGRESS);//讓意圖攜帶播放時長intent1.putExtra(DURATION, mp.getDuration());//發送廣播sendBroadcast(intent1);} catch (IOException e) {e.printStackTrace();}//返回非粘性服務return Service.START_NOT_STICKY;}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}/*** 銷毀回調方法*/@Overridepublic void onDestroy() {super.onDestroy();// 釋放播放器if (mp != null) {mp.release();mp = null;}//注銷廣播接收者unregisterReceiver(receiver);//設置線程循環控制變量isRunning = false;//銷毀子線程thread = null;}/*** 播放方法*/private void play() {try {// 重置媒體播放器mp.reset();//獲取當前播放的音樂名musicName = musicList.get(app.getCurrentMusicIndex()).getMusicName();// 設置播放源(完整音樂名 = 音樂目錄 + 音樂名)mp.setDataSource(musicName);// 緩沖播放源(從存儲卡加載到內存)mp.prepare();// 定位到暫停時的播放位置mp.seekTo(app.getCurrentPosition());// 啟動音樂的播放mp.start();} catch (IOException e) {e.printStackTrace();}}/*** 上一曲*/private void previousMusic() {//更新索引if (app.getCurrentMusicIndex() > 0) {app.setCurrentMusicIndex(app.getCurrentMusicIndex() - 1);} else {app.setCurrentMusicIndex(musicList.size() - 1);}//位置歸零app.setCurrentPosition(0);//調用播放方法play();}/*** 下一曲*/private void nextMusic() {//更新索引if (app.getCurrentMusicIndex() < musicList.size() - 1) {app.setCurrentMusicIndex(app.getCurrentMusicIndex() + 1);} else {app.setCurrentMusicIndex(0);}//播放位置歸零app.setCurrentPosition(0);play();}/*** 暫停方法*/private void pause() {// 暫停播放mp.pause();// 保存音樂播放的當前位置app.setCurrentPosition(mp.getCurrentPosition());// 創建意圖Intent intent = new Intent();//設置廣播頻道更新進度intent.setAction(INTENT_ACTION_UPDATE_PROGRESS);//攜帶播放時長數據intent.putExtra(DURATION, mp.getDuration());//控制圖標intent.putExtra(CONTROL_ICON, R.drawable.play_button_selector);//發送廣播sendBroadcast(intent);}/*** 音樂廣播接收者*/private class MusicReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//獲取意圖動作(廣播頻道)String action = intent.getAction();//對廣播頻道非空判斷if (action != null) {switch (action) {case INTENT_ACTION_PLAY://單擊列表項//進度歸零app.setCurrentPosition(0);//播放play();break;case INTENT_ACTION_PLAY_OR_PAUSE://單擊播放|暫停按鈕//判斷是否播放if (mp.isPlaying()) {pause();} else {play();}break;case INTENT_ACTION_PREVIOUS://上一曲//上一曲previousMusic();break;case INTENT_ACTION_NEXT://下一曲//切換下一曲nextMusic();break;}}}} }18、在項目清單文件里注冊音樂播放服務
19、主界面類 - MainActivity
package com.example.musicplayerv05.ui;import android.Manifest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat;import com.example.musicplayerv05.R; import com.example.musicplayerv05.Service.MusicPlayService; import com.example.musicplayerv05.adapter.MusicAdapter; import com.example.musicplayerv05.app.AppConstants; import com.example.musicplayerv05.app.MusicPlayerApplication; import com.example.musicplayerv05.entity.Music;import java.util.List;public class MainActivity extends AppCompatActivity implements AppConstants {private String musicName; // 音樂文件名private TextView tvMusicName; // 音樂名標簽private Button btnPlayOrPause; // 播放|暫停按鈕private MusicReceiver receiver;//廣播接收器private TextView tvCurrentPosition; // 顯示當前播放位置的標簽private TextView tvDuration; // 顯示音樂播放時長的標簽private ProgressBar pbMusicProgress; // 音樂播放進度條private List<Music> musicList;//音樂數據源private ListView lvMusicName;//音樂名控件列表private MusicAdapter adapter;//適配器private MusicPlayerApplication app;//音樂播放器應用程序private ProgressBar pbScanMusic;//掃描存儲卡進度條private TextView tvScanMusic;//掃描存儲卡音樂標簽@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//獲取實例lvMusicName = findViewById(R.id.lvMusicName);btnPlayOrPause = findViewById(R.id.btnPlayOrPause);tvMusicName = findViewById(R.id.tvMusicName);tvCurrentPosition = findViewById(R.id.tvCurrentPosition);tvDuration = findViewById(R.id.tvDuration);pbMusicProgress = findViewById(R.id.pbMusicProgress);pbScanMusic = findViewById(R.id.pbScanMusic);tvScanMusic = findViewById(R.id.tvScanMusic);//獲取音樂播放器應用程序對象app = (MusicPlayerApplication) getApplication();// 定義存儲讀寫權限數組String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};// 檢查是否有讀權限int permission = ActivityCompat.checkSelfPermission(this, PERMISSIONS_STORAGE[0]);// 如果沒有授權,那么就請求讀權限if (permission != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 0);return;}//啟動填充音樂播放列表異步任務new FillMusicListTask().execute();lvMusicName.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {//獲取音樂索引app.setCurrentMusicIndex(position);//播放進度歸零app.setCurrentPosition(0);//獲取音樂名musicName = app.getMusicList().get(position).getMusicName();//設置音樂名,去掉路徑和擴展名tvMusicName.setText("No." + (app.getCurrentMusicIndex() + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));//創建意圖Intent intent = new Intent();//設置廣播頻道:播放intent.setAction(INTENT_ACTION_PLAY);//發送廣播sendBroadcast(intent);}});//創建音樂廣播接收器receiver = new MusicReceiver();//創建過濾器IntentFilter filter = new IntentFilter();//通過過濾器添加廣播頻道filter.addAction(INTENT_ACTION_UPDATE_PROGRESS);//注冊廣播接收器registerReceiver(receiver,filter);}/*** 音樂廣播接收器*/private class MusicReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//獲取廣播頻道String action = intent.getAction();//判斷廣播頻道是否為空if (action != null){//根據不同廣播頻道執行不同操作if (INTENT_ACTION_UPDATE_PROGRESS.equals(action)){//獲取播放時長int duration = intent.getIntExtra(DURATION,0);//獲取播放圖標int controlIcon = intent.getIntExtra(CONTROL_ICON,R.drawable.play_button_selector);//計算進度int progress = app.getCurrentPosition() * 100 / duration;//獲取音樂名musicName = app.getMusicList().get(app.getCurrentMusicIndex()).getMusicName();//設置音樂名,去掉多余部分tvMusicName.setText("No."+(app.getCurrentMusicIndex()+1)+" "+ musicName.substring(musicName.lastIndexOf("/")+1,musicName.lastIndexOf(".")));//設置進度標簽tvCurrentPosition.setText(app.getFormatTime(app.getCurrentPosition()));//設置時長標簽tvDuration.setText(app.getFormatTime(duration));//設置進度條pbMusicProgress.setProgress(progress);//設置按鈕圖標btnPlayOrPause.setBackgroundResource(controlIcon);}}}}/*** 填充音樂列表異步任務類*/private class FillMusicListTask extends AsyncTask<Void, Integer, Void> {/*** 耗時工作執行前*/@Overrideprotected void onPreExecute() {super.onPreExecute();//設置進度條屬性pbScanMusic.setVisibility(View.VISIBLE);//設置文字屬性tvScanMusic.setVisibility(View.VISIBLE);}protected Void doInBackground(Void... voids) {musicList = app.getMusicList();for (long i = 0; i < 2000000000; i++) {}return null;}/*** 耗時工作后* @param aVoid*/@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);pbScanMusic.setVisibility(View.GONE);tvScanMusic.setVisibility(View.GONE);//判斷列表是否為空if (musicList.size() > 0) {//創建適配器adapter = new MusicAdapter(MainActivity.this, musicList);//設置適配器lvMusicName.setAdapter(adapter);//獲取音樂名標簽內容(默認為第一首)musicName = musicList.get(0).getMusicName();//設置播放音樂名tvMusicName.setText("No." + (app.getCurrentMusicIndex() + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));Intent intent = new Intent(MainActivity.this, MusicPlayService.class);startService(intent);} else {Toast.makeText(MainActivity.this, "存儲卡Music目錄里沒有音樂文件!", Toast.LENGTH_SHORT).show();}}}/***上一曲* @param view*/public void doPrevious(View view){//創建意圖Intent intent = new Intent();//設置廣播頻道intent.setAction(INTENT_ACTION_PREVIOUS);//發送廣播sendBroadcast(intent);}/***下一曲* @param view*/public void doNext(View view){//創建意圖Intent intent = new Intent();//設置廣播頻道intent.setAction(INTENT_ACTION_NEXT);//發送廣播sendBroadcast(intent);}/*** 播放暫停* @param view*/public void doPlayOrPause(View view){//創建意圖Intent intent = new Intent();//設置廣播頻道intent.setAction(INTENT_ACTION_PLAY_OR_PAUSE);//發送廣播sendBroadcast(intent);}/*** 銷毀回調方法*/@Overrideprotected void onDestroy(){super.onDestroy();//停止音樂播放服務stopService(new Intent(MainActivity.this, MusicPlayService.class));//注銷廣播接收器if (receiver != null){unregisterReceiver(receiver);}} }總結
以上是生活随笔為你收集整理的安卓实训项目:基于储存卡音乐播放器实训报告5.0的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓实训项目:基于储存卡音乐播放器实训报
- 下一篇: 钢材的弹性模量E等于多少?