安卓实训项目:基于储存卡音乐播放器实训报告4.0
生活随笔
收集整理的這篇文章主要介紹了
安卓实训项目:基于储存卡音乐播放器实训报告4.0
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
功能要求
在基于存儲卡音樂播放器V0.3基礎上,作如下修改:
1、創(chuàng)建方法能掃描存儲卡上所有mp3文件(采用遞歸算法) ----完成
2、用自定義應用程序類存放全局數(shù)據(jù)和方法 ----完成
3、利用異步任務來完成耗時的存儲卡掃描工作----完成
說明:模擬器存儲卡上目錄少,掃描很快就完成,幾乎看不到等待的進度條,最好在真機上運行程序進行測試。----真機測試不讀目錄可能和安卓版本太高有關,測試設備安卓11.
一、運行效果
二、實現(xiàn)步驟
.將圖片素材拷貝到drawable目錄與mipmap目錄
創(chuàng)建音樂名列表項模板music_name_list_item.xml
創(chuàng)建entity子包,在里面創(chuàng)建音樂實體類Music
public class Music {private String musicName; // 音樂名public String getMusicName() {return musicName;}public void setMusicName(String musicName) {this.musicName = musicName;}@Overridepublic String toString() {return "Music{" +"musicName='" + musicName + '\'' +'}';} } 創(chuàng)建app子包,在里面創(chuàng)建音樂播放器應用程序類MusicPlayerApplication ``import android.app.Application; import android.os.Environment;import net.yq.sdcardmusicplayerv04.entity.Music;import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List;public class MusicPlayerApplication extends Application {private SimpleDateFormat sdf;//簡單日期格式@Overridepublic void onCreate() {super.onCreate();sdf = new SimpleDateFormat("mm:ss");}public String getFormatTime(int time) {return sdf.format(time);}/*** 生成指定目錄下某種文件的文件列表** @param dir* @param suffix* @param typeFileList*/public void makeTypeFileList(File dir, String suffix, List<String> typeFileList) {//獲取指定目錄下的File數(shù)組(File既可以指向目錄,也可以指向文件)File[] files = dir.listFiles();//遍歷File數(shù)組for (File file : files) {//判斷file是否是文件if (file.isFile()) {//file是文件//按照后綴過濾文件if (file.getName().endsWith(suffix)) {//將滿足條件的文件添加到文件列表typeFileList.add(file.getAbsolutePath());}} else {//file是目錄//目錄為空,遞歸調(diào)用if (file.list() != null) {makeTypeFileList(file, suffix, typeFileList);}}}}/*** 獲取音樂列表* @return*/public List<Music> getMusicList(){//聲明音樂列表List<Music> musicList= null;//獲取外置存儲卡目錄File sdRootDir = Environment.getExternalStorageDirectory();//創(chuàng)建后綴字符串String suffix = ".mp3";//創(chuàng)建音樂文件列表List<String> musicFileList = new ArrayList<>();//調(diào)用方法,生成指定目錄下某種類型文件列表makeTypeFileList(sdRootDir,suffix,musicFileList);//判斷音樂文件列表元素是否有元素if (musicFileList.size()>0){// 實例化音樂列表musicList = new ArrayList<>();//遍歷音樂文件列表for (String musicFile : musicFileList){//創(chuàng)建音樂實體Music music =new Music();//設置實體屬性music.setMusicName(musicFile);//將音樂實體添加到音樂列表musicList.add(music);}}//返回音樂列表return musicList;} } .在項目清單文件里個音樂播放器應用程序類注冊并授權(quán)讀外置存儲卡  創(chuàng)建adapter子包,在里面創(chuàng)建音樂適配器MusicAdapter```cpp import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView;import net.yq.sdcardmusicplayerv04.R; import net.yq.sdcardmusicplayerv04.entity.Music;import java.util.List;/*** 音樂適配器**/ public class MusicAdapter extends BaseAdapter {private final Context context; // 上下文private final List<Music> musicList;// 音樂列表/*** 構(gòu)造方法** @param context* @param musicList*/public MusicAdapter(Context context, List<Music> musicList) {this.context = context;this.musicList = musicList;}/*** 個數(shù)** @return*/@Overridepublic int getCount() {return musicList.size();}/*** 列表項** @param position* @return*/@Overridepublic Object getItem(int position) {return musicList.get(position);}/*** 列表項id** @param position* @return*/@Overridepublic long getItemId(int position) {return position;}/*** 列表項視圖** @param position* @param convertView* @param parent* @return*/@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 聲明視圖容器ViewHolder holder = null;// 判斷轉(zhuǎn)換視圖是否為空if (convertView == null) {// 將列表項模板映射成轉(zhuǎn)換視圖convertView = LayoutInflater.from(context).inflate(R.layout.music_name_list_item, null);// 創(chuàng)建視圖容器對象holder = new ViewHolder();// 實例化轉(zhuǎn)換視圖里的控件holder.tvMusicName = convertView.findViewById(R.id.tvMusicName);// 將視圖容器附加到轉(zhuǎn)換視圖convertView.setTag(holder);} else {// 從轉(zhuǎn)換視圖里取出視圖容器holder = (ViewHolder) convertView.getTag();}// 獲取列表項要顯示的數(shù)據(jù)Music music = musicList.get(position);// 設置列表項控件的屬性(去掉路徑和擴展名)holder.tvMusicName.setText(music.getMusicName().substring(music.getMusicName().lastIndexOf("/") + 1, music.getMusicName().lastIndexOf(".")));// 返回轉(zhuǎn)換視圖return convertView;}/*** 視圖容器*/private static class ViewHolder {TextView tvMusicName;} } 主界面類 - MainActivity```cpp package com.example.musicplayerv04.ui;import android.Manifest; import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; 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.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat;import com.example.musicplayerv04.R; import com.example.musicplayerv04.adapter.MusicAdapter; import com.example.musicplayerv04.app.MusicPlayerApplication; import com.example.musicplayerv04.entity.Music;import java.io.IOException; import java.util.List;/*** 功能:基于存儲卡音樂播放器V4.0* 作者:劉宇* 日期:2021年01月05日*/public class MainActivity extends AppCompatActivity {private MediaPlayer mp; // 媒體播放器private String musicName; // 音樂文件名private TextView tvMusicName; // 音樂名標簽private Button btnPlayOrPause; // 播放|暫停按鈕private int currentPosition; // 音樂當前播放位置private TextView tvCurrentPosition; // 顯示當前播放位置的標簽private TextView tvDuration; // 顯示音樂播放時長的標簽private ProgressBar pbMusicProgress; // 音樂播放進度條private Thread thread; // 線程private Handler handler; // 消息處理器private boolean isRunning; // 線程循環(huán)控制變量private ListView lvMusicName; // 音樂名列表控件private List<Music> musicList; // 音樂列表(數(shù)據(jù)源)private MusicAdapter adapter; // 音樂適配器private int musicIndex; // 音樂索引(表明在音樂列表中的位置)private MusicPlayerApplication app; // 音樂播放器應用程序?qū)ο?/span>private ProgressBar pbScanMusic; // 掃描存儲卡音樂進度條private TextView tvScanMusic; // 掃描存儲卡音樂標簽(提示用戶耐心等待)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 通過資源標識符獲取控件實例lvMusicName = findViewById(R.id.lvMusicName);tvMusicName = findViewById(R.id.tvMusicName);btnPlayOrPause = findViewById(R.id.btnPlayOrPause);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);// 初始化播放器mp = new MediaPlayer();// 獲取音樂播放器應用程序?qū)ο?/span>app = (MusicPlayerApplication) getApplication();// 定義存儲讀寫權(quán)限數(shù)組String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};// 檢查是否有讀權(quán)限final int permission = ActivityCompat.checkSelfPermission(this, PERMISSIONS_STORAGE[0]);// 如果沒有授權(quán),那么就請求讀權(quán)限if (permission != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 0);return;}// 啟動填充音樂播放列表異步任務new FillMusicListTask().execute();// 設置線程循環(huán)控制變量為真isRunning = true;// 創(chuàng)建子線程,定時發(fā)送消息thread = new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {// 向主線程發(fā)送消息handler.sendEmptyMessage(0x001);try {// 讓線程睡眠500毫秒Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}});// 啟動子線程thread.start();// 創(chuàng)建消息處理器,接收子線程發(fā)送的消息handler = new Handler() {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);// 根據(jù)子線程發(fā)送的消息進行相應處理if (msg.what == 0x001) {// 判斷音樂是否在播放if (mp != null && mp.isPlaying()) {// 獲取當前播放位置currentPosition = mp.getCurrentPosition();// 更新音樂播放進度條的進度值pbMusicProgress.setProgress(currentPosition);// 更新當前播放位置標簽的內(nèi)容tvCurrentPosition.setText(app.getFormatTime(currentPosition));}}}};// 給音樂列表控件注冊監(jiān)聽器lvMusicName.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {// 獲取音樂索引musicIndex = position;// 當前播放位置歸零currentPosition = 0;try {// 調(diào)用播放方法play();} catch (IOException e) {e.printStackTrace();}}});// 給媒體播放器注冊完成監(jiān)聽器mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mediaPlayer) {try {// 切換到下一首nextMusic();} catch (IOException e) {e.printStackTrace();}}});}/*** 填充音樂列表異步任務類*/private class FillMusicListTask extends AsyncTask<Void, Integer, Void> {/*** 耗時工作執(zhí)行前*/@Overrideprotected void onPreExecute() {super.onPreExecute();// 顯示掃描音樂進度條pbScanMusic.setVisibility(View.VISIBLE);// 顯示掃描音樂標簽tvScanMusic.setVisibility(View.VISIBLE);}@Overrideprotected Void doInBackground(Void... voids) {// 獲取音樂列表musicList = app.getMusicList();// 故意耗時,要不然掃描太快結(jié)束for (long i = 0; i < 2000000000; i++) {}return null;}/*** 耗時工作執(zhí)行后** @param aVoid*/@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);// 隱藏掃描音樂進度條pbScanMusic.setVisibility(View.GONE);// 隱藏掃描音樂標簽tvScanMusic.setVisibility(View.GONE);// 判斷音樂列表是否有元素if (musicList.size() > 0) {// 創(chuàng)建音樂適配器adapter = new MusicAdapter(MainActivity.this, musicList);// 給音樂列表控件設置適配器lvMusicName.setAdapter(adapter);// 獲取當前要播放的音樂名(默認是音樂播放列表的第一首)musicName = musicList.get(0).getMusicName();// 設置音樂名標簽內(nèi)容,去掉路徑和擴展名,添加序號tvMusicName.setText("No." + (musicIndex + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));try {// 設置播放源mp.setDataSource(musicName);// 緩沖播放源(從存儲卡加載到內(nèi)存)mp.prepare();// 設置當前播放位置標簽tvCurrentPosition.setText(app.getFormatTime(mp.getCurrentPosition()));// 設置音樂播放時長標簽tvDuration.setText(app.getFormatTime(mp.getDuration()));// 數(shù)字化音樂播放進度條的最大值pbMusicProgress.setMax(mp.getDuration());} catch (IOException e) {e.printStackTrace();}} else {// 提示用戶沒有音樂文件Toast.makeText(MainActivity.this, "外置存儲卡上沒有音樂文件!", Toast.LENGTH_SHORT);}}}/*** 播放方法*/private void play() throws IOException {// 重置媒體播放器mp.reset();// 獲取當前播放的音樂名musicName = musicList.get(musicIndex).getMusicName();// 設置音樂名標簽內(nèi)容,去掉路徑和擴展名,添加序號tvMusicName.setText("No." + (musicIndex + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));// 設置播放源mp.setDataSource(musicName);// 緩沖播放源(從存儲卡加載到內(nèi)存)mp.prepare();// 設置當前播放位置標簽tvCurrentPosition.setText(app.getFormatTime(mp.getCurrentPosition()));// 設置音樂播放時長標簽tvDuration.setText(app.getFormatTime(mp.getDuration()));// 數(shù)字化音樂播放進度條的最大值pbMusicProgress.setMax(mp.getDuration());// 定位到暫停時的播放位置mp.seekTo(currentPosition);// 啟動音樂的播放mp.start();// 按鈕圖標由【播放】圖標切換到【暫停】圖標btnPlayOrPause.setBackgroundResource(R.drawable.pause_button_selector);}/*** 暫停方法*/private void pause() {// 暫停播放mp.pause();// 保存音樂播放的當前位置currentPosition = mp.getCurrentPosition();// 按鈕圖標由【暫停】圖標切換到【播放】圖標btnPlayOrPause.setBackgroundResource(R.drawable.play_button_selector);}/*** 上一首音樂*/private void previousMusic() throws IOException {// 更新音樂索引if (musicIndex > 0) {musicIndex--;} else {musicIndex = musicList.size() - 1;}// 當前播放位置歸零currentPosition = 0;// 調(diào)用播放方法play();}/*** 下一首音樂*/private void nextMusic() throws IOException {// 更新音樂索引if (musicIndex < musicList.size() - 1) {musicIndex++;} else {musicIndex = 0;}// 當前播放位置歸零currentPosition = 0;// 調(diào)用播放方法play();}/*** 播放|暫停按鈕單擊事件處理方法** @param view*/public void doPlayOrPause(View view) throws IOException {// 判斷音樂是否在播放if (mp.isPlaying()) {// 暫停音樂pause();} else {// 播放音樂play();}}/*** 上一首按鈕單擊事件處理方法** @param view*/public void doPrevious(View view) throws IOException {previousMusic();}/*** 下一首按鈕單擊事件處理方法** @param view*/public void doNext(View view) throws IOException {nextMusic();}/*** 銷毀回調(diào)方法,釋放資源*/@Overrideprotected void onDestroy() {super.onDestroy();// 停止線程isRunning = false;// 銷毀線程thread = null;// 判斷音樂是否在播放if (mp.isPlaying()) {mp.stop();}// 釋放媒體播放器mp.release();// 銷毀媒體播放器mp = null;} }總結(jié)
以上是生活随笔為你收集整理的安卓实训项目:基于储存卡音乐播放器实训报告4.0的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓实训项目:音乐播放器3.0——实训报
- 下一篇: 安卓实训项目:基于储存卡音乐播放器实训报