100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 安卓实训项目:基于储存卡音乐播放器实训报告4.0

安卓实训项目:基于储存卡音乐播放器实训报告4.0

时间:2022-02-01 19:59:20

相关推荐

安卓实训项目:基于储存卡音乐播放器实训报告4.0

功能要求

在基于存储卡音乐播放器V0.3基础上,作如下修改:

1、创建方法能扫描存储卡上所有mp3文件(采用递归算法) ----完成

2、用自定义应用程序类存放全局数据和方法 ----完成

3、利用异步任务来完成耗时的存储卡扫描工作----完成

说明:模拟器存储卡上目录少,扫描很快就完成,几乎看不到等待的进度条,最好在真机上运行程序进行测试。----真机测试不读目录可能和安卓版本太高有关,测试设备安卓11.

一、运行效果

二、实现步骤

.将图片素材拷贝到drawable目录与mipmap目录

创建音乐名列表项模板music_name_list_item.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp"><TextViewandroid:id="@+id/tvMusicName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20sp"/></LinearLayout>

创建entity子包,在里面创建音乐实体类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 + '\'' +'}';}}创建app子包,在里面创建音乐播放器应用程序类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数组(File既可以指向目录,也可以指向文件)File[] files = dir.listFiles();//遍历File数组for (File file : files) {//判断file是否是文件if (file.isFile()) {//file是文件//按照后缀过滤文件if (file.getName().endsWith(suffix)) {//将满足条件的文件添加到文件列表typeFileList.add(file.getAbsolutePath());}} else {//file是目录//目录为空,递归调用if (file.list() != null) {makeTypeFileList(file, suffix, typeFileList);}}}}/*** 获取音乐列表* @return*/public List<Music> getMusicList(){//声明音乐列表List<Music> musicList= null;//获取外置存储卡目录File sdRootDir = Environment.getExternalStorageDirectory();//创建后缀字符串String suffix = ".mp3";//创建音乐文件列表List<String> musicFileList = new ArrayList<>();//调用方法,生成指定目录下某种类型文件列表makeTypeFileList(sdRootDir,suffix,musicFileList);//判断音乐文件列表元素是否有元素if (musicFileList.size()>0){// 实例化音乐列表musicList = new ArrayList<>();//遍历音乐文件列表for (String musicFile : musicFileList){//创建音乐实体Music music =new Music();//设置实体属性music.setMusicName(musicFile);//将音乐实体添加到音乐列表musicList.add(music);}}//返回音乐列表return musicList;}}.在项目清单文件里个音乐播放器应用程序类注册并授权读外置存储卡![在这里插入图片描述](https://img-/0111202617103.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUxMDA4MDAx,size_16,color_FFFFFF,t_70)创建adapter子包,在里面创建音乐适配器MusicAdapter```cppimport 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;// 音乐列表/*** 构造方法** @param context* @param musicList*/public MusicAdapter(Context context, List<Music> musicList) {this.context = context;this.musicList = musicList;}/*** 个数** @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;// 判断转换视图是否为空if (convertView == null) {// 将列表项模板映射成转换视图convertView = LayoutInflater.from(context).inflate(R.layout.music_name_list_item, null);// 创建视图容器对象holder = new ViewHolder();// 实例化转换视图里的控件holder.tvMusicName = convertView.findViewById(R.id.tvMusicName);// 将视图容器附加到转换视图convertView.setTag(holder);} else {// 从转换视图里取出视图容器holder = (ViewHolder) convertView.getTag();}// 获取列表项要显示的数据Music music = musicList.get(position);// 设置列表项控件的属性(去掉路径和扩展名)holder.tvMusicName.setText(music.getMusicName().substring(music.getMusicName().lastIndexOf("/") + 1, music.getMusicName().lastIndexOf(".")));// 返回转换视图return convertView;}/*** 视图容器*/private static class ViewHolder {TextView tvMusicName;}}主界面类 - MainActivity```cpppackage 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* 作者:刘宇* 日期: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; // 线程循环控制变量private ListView lvMusicName; // 音乐名列表控件private List<Music> musicList; // 音乐列表(数据源)private MusicAdapter adapter; // 音乐适配器private int musicIndex; // 音乐索引(表明在音乐列表中的位置)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);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();// 获取音乐播放器应用程序对象app = (MusicPlayerApplication) getApplication();// 定义存储读写权限数组String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};// 检查是否有读权限final int permission = ActivityCompat.checkSelfPermission(this, PERMISSIONS_STORAGE[0]);// 如果没有授权,那么就请求读权限if (permission != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 0);return;}// 启动填充音乐播放列表异步任务new FillMusicListTask().execute();// 设置线程循环控制变量为真isRunning = true;// 创建子线程,定时发送消息thread = new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {// 向主线程发送消息handler.sendEmptyMessage(0x001);try {// 让线程睡眠500毫秒Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}});// 启动子线程thread.start();// 创建消息处理器,接收子线程发送的消息handler = new Handler() {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);// 根据子线程发送的消息进行相应处理if (msg.what == 0x001) {// 判断音乐是否在播放if (mp != null && mp.isPlaying()) {// 获取当前播放位置currentPosition = mp.getCurrentPosition();// 更新音乐播放进度条的进度值pbMusicProgress.setProgress(currentPosition);// 更新当前播放位置标签的内容tvCurrentPosition.setText(app.getFormatTime(currentPosition));}}}};// 给音乐列表控件注册监听器lvMusicName.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {// 获取音乐索引musicIndex = position;// 当前播放位置归零currentPosition = 0;try {// 调用播放方法play();} catch (IOException e) {e.printStackTrace();}}});// 给媒体播放器注册完成监听器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> {/*** 耗时工作执行前*/@Overrideprotected void onPreExecute() {super.onPreExecute();// 显示扫描音乐进度条pbScanMusic.setVisibility(View.VISIBLE);// 显示扫描音乐标签tvScanMusic.setVisibility(View.VISIBLE);}@Overrideprotected 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." + (musicIndex + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));try {// 设置播放源mp.setDataSource(musicName);// 缓冲播放源(从存储卡加载到内存)mp.prepare();// 设置当前播放位置标签tvCurrentPosition.setText(app.getFormatTime(mp.getCurrentPosition()));// 设置音乐播放时长标签tvDuration.setText(app.getFormatTime(mp.getDuration()));// 数字化音乐播放进度条的最大值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();// 设置音乐名标签内容,去掉路径和扩展名,添加序号tvMusicName.setText("No." + (musicIndex + 1) + " " + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));// 设置播放源mp.setDataSource(musicName);// 缓冲播放源(从存储卡加载到内存)mp.prepare();// 设置当前播放位置标签tvCurrentPosition.setText(app.getFormatTime(mp.getCurrentPosition()));// 设置音乐播放时长标签tvDuration.setText(app.getFormatTime(mp.getDuration()));// 数字化音乐播放进度条的最大值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;// 调用播放方法play();}/*** 下一首音乐*/private void nextMusic() throws IOException {// 更新音乐索引if (musicIndex < musicList.size() - 1) {musicIndex++;} else {musicIndex = 0;}// 当前播放位置归零currentPosition = 0;// 调用播放方法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();}/*** 销毁回调方法,释放资源*/@Overrideprotected void onDestroy() {super.onDestroy();// 停止线程isRunning = false;// 销毁线程thread = null;// 判断音乐是否在播放if (mp.isPlaying()) {mp.stop();}// 释放媒体播放器mp.release();// 销毁媒体播放器mp = null;}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。