安卓实训项目:基于存储卡音乐播放器V0.5

安卓实训项目:基于存储卡音乐播放器V0.5
一、知识点
1.标签(TextView)
2.按钮(Button)
3.媒体播放器(MediaPlayer)
4.进度条(ProgressBar)
5.线程(Thread)
6.消息处理器(Handler)
7.列表视图(ListView)
8.应用程序(Application)
9.递归算法(Recursive Algorithm)
10.异步任务(AsyncTask)
11.服务(Service)
12.广播接受者(BroadcastReceiver)
13.布局

二、功能
•播放存储卡上一首音乐 ,上一首与下一首可切换
•播放|暂停按钮,可切换
•显示要播放的音乐名
•要求窗口有背景图片
•有进度条 播放时长、位置
•播放进度清零
•自动切换到下一首音乐播放
•扫描存储卡上所有mp3文件(递归算法)
•使用应用程序存放数据
•利用应用程序来保存广播频道

三、创建安卓应用
在这里插入图片描述

在这里插入图片描述
1、将MP3音频文件放到存储卡指定位置
•从电脑上添加自己喜欢的MP3音频文件到Music目录
2、将图片素材拷贝到Drawable目录
3、创建按钮背景图片选择器
(一)、创建播放一个背景图片选择器按钮
在这里插入图片描述
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?> (二)、创建暂停一个背景图片选择器按钮 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024404561.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) <?xml version="1.0" encoding="utf-8"?> (三)、创建下一首背景图片选择器按钮 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024442624.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) <?xml version="1.0" encoding="utf-8"?> (四)、创建上一首背景图片选择器按钮 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024514627.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) 4、在项目清单文件里设置安卓应用的图标 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024542145.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021011202455925.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) 5、主布局 <?xml version="1.0" encoding="utf-8"?>
</LinearLayout>

<ListView
    android:id="@+id/lvMusicName"
    android:layout_width="match_parent"
    android:layout_height="500dp"
    android:layout_marginBottom="16dp"
    android:layout_weight="8" />

<TextView
    android:id="@+id/tvMusicName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="0.5"
    android:textColor="#03A9F4"
    android:textSize="20sp" />

<LinearLayout
    android: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">

    <TextView
        android:id="@+id/tvCurrentPosition"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="#ff0000" />

    <ProgressBar
        android:id="@+id/pbMusicProgress"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="6" />

    <TextView
        android:id="@+id/tvDuration"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="#ff00ff" />
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="0.5"
    android:gravity="center"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btnPrevious"
        android:layout_width="60dp"
        android:layout_height="50dp"
        android:background="@drawable/previous_button_selector"
        android:onClick="doPrevious" />

    <Button
        android:id="@+id/btnPlayOrPause"
        android:layout_width="60dp"
        android:layout_height="50dp"
        android:background="@drawable/play_button_selector"
        android:onClick="doPlayOrPause" />

    <Button
        android:id="@+id/btnNext"
        android:layout_width="60dp"
        android:layout_height="50dp"
        android:background="@drawable/next_button_selector"
        android:onClick="doNext" />
</LinearLayout>
6、字符串资源文件String.xml ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024639491.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) 基于存储卡音乐播放器v0.5 扫描外置存储卡上全部MP3,请耐心等待...... 7、创建音乐 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024708679.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024729723.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) <?xml version="1.0" encoding="utf-8"?>
<TextView
    android:id="@+id/tvMusicName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="20sp"/>
8、创建ui子包,将MainActivity拖进ui子包 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024800572.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210112024821604.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MjA0MzAy,size_16,color_FFFFFF,t_70#pic_center) 13、创建entity子包 14、在entity子包里面创建音乐实体类Music package net.tp.sdcard_musicplayer_v05.entity;

public class Music {

private String musicName; // 音乐名

public String getMusicName() {
    return musicName;
}

public void setMusicName(String musicName) {
    this.musicName = musicName;
}

@Override
public String toString() {
    return "Music{" +
            "musicName='" + musicName + '\'' +
            '}';
}

}
15、创建app子包
在这里插入图片描述
16、在app子包里面创建音乐播放器应用程序类MusicPlayerApplication
package net.tp.sdcard_musicplayer_v05.app;

import android.app.Application;
import android.os.Environment;

import net.tp.sdcard_musicplayer_v05.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; // 简单日期格式
private int currentMusicIndex; // 当前音乐索引
private int currentPosition; // 当前播放位置

@Override
public void onCreate() {
    super.onCreate();
    // 实例化简单日期格式
    sdf = new SimpleDateFormat("mm:ss");
}

public int getCurrentMusicIndex() {
    return currentMusicIndex;
}

public void setCurrentMusicIndex(int currentMusicIndex) {
    this.currentMusicIndex = currentMusicIndex;
}

public int getCurrentPosition() {
    return currentPosition;
}

public void setCurrentPosition(int currentPosition) {
    this.currentPosition = currentPosition;
}

/**
 * 获取格式化时间
 *
 * @param time 单位是毫秒
 * @return 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;
}

}
17、在项目清单文件里个音乐播放器应用程序类注册
在这里插入图片描述
18、创建adapter子包
在这里插入图片描述
19、在adapter子包里面创建音乐适配器MusicAdapter
在这里插入图片描述
package net.tp.sdcard_musicplayer_v05.adapter;

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.tp.sdcard_musicplayer_v05.R;
import net.tp.sdcard_musicplayer_v05.entity.Music;

import java.util.List;

public class MusicAdapter extends BaseAdapter {
private Context context; // 上下文
private List musicList; // 音乐列表

/**
 * 构造方法
 *
 * @param context
 * @param musicList
 */
public MusicAdapter(Context context, List<Music> musicList) {
    this.context = context;
    this.musicList = musicList;
}

@Override
public int getCount() {
    return musicList.size();
}

@Override
public Object getItem(int position) {
    return musicList.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public 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;
}

}
20、在app子包常见应用程序常量接口 - AppConstants
在这里插入图片描述
package net.tp.sdcard_musicplayer_v05.app;
/**

  • 功能:应用程序常量接口
  • 日期:2021年01月06日
    */

public interface AppConstants {
String TAG=“net.tp.sdcard_musicplayer_v05”;//应用程序标记
String INTENT_ACTION_PREVIOUS =TAG +".intent.action.PREVIOUS";//广播频道常量:播放上一首
String INTENT_ACTION_PLAY =TAG +".intent.action.PLAY";//广播频道常量:播放
String INTENT_ACTION_PLAY_OR_PAUSE =TAG +".intent.action.PLAY_OR_PAUSE";//广播频道常量:播放或暂停
String INTENT_ACTION_NEXT =TAG +".intent.action.NEXT";//广播频道常量:播放下一首
String INTENT_ACTION_UPDATE_PROGRESS =TAG +".intent.action.UPDATE_PROGRESS";//广播频道常量:更新播放进度
String CONTROL_ICON =“control_icon”;//控制图标名称常量
String DURATION =“duration”;//播放时长名称常量
String CURRENT_POSITION=“current_position”;//当前播放位置名称常量
}

20、在项目清单文件里授权读外置存储卡
在这里插入图片描述
21、创建service子包
22、在service子包里面创建音乐播放服务类 - MusicPlayService
在这里插入图片描述

package net.tp.sdcard_musicplayer_v05.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 net.tp.sdcard_musicplayer_v05.R;
import net.tp.sdcard_musicplayer_v05.app.AppConstants;
import net.tp.sdcard_musicplayer_v05.app.MusicPlayerApplication;
import net.tp.sdcard_musicplayer_v05.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;//音乐广播接收者


@Override
public void onCreate() {
    super.onCreate();
    //获取音乐播放器应用程序对象
    app= (MusicPlayerApplication) getApplication();
    //获取音乐列表
    musicList=app.getMusicList();

    //创建媒体播放器
    mp=new MediaPlayer();
    //给媒体播放器注册完成监听器
    mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            //切换到下一首音乐
            nextMusic();
        }
    });

    //设置线程循环控制变量为真
    isRunning=true;
    //创建更新播放进度的线程
    thread=new Thread(new Runnable(){
        @Override
        public void run() {
            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);


}



@Override
public 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
@Override
public IBinder onBind(Intent intent) {
    return null;
}






/**
 * 销毁回调方法,释放资源
 */
@Override
public 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.getCurrentPosition() > 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 {
    @Override
    public 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;

            }
        }
    }
}

}

21、主界面类 - MainActivity
package net.tp.sdcard_musicplayer_v05.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 net.tp.sdcard_musicplayer_v05.R;
import net.tp.sdcard_musicplayer_v05.adapter.MusicAdapter;
import net.tp.sdcard_musicplayer_v05.app.AppConstants;
import net.tp.sdcard_musicplayer_v05.app.MusicPlayerApplication;
import net.tp.sdcard_musicplayer_v05.entity.Music;
import net.tp.sdcard_musicplayer_v05.service.MusicPlayService;

import java.util.List;

public class MainActivity extends AppCompatActivity implements AppConstants {

private String musicName; //音乐文件名
private TextView tvMusicName ;//音乐名标签
private Button btnP1ayOrPause; //播放|暂停按钮
private MusicReceiver receiver; //音乐广播接收器
private TextView tvCurrentPosition; //显示当前播放位的标签
private TextView tvDuration; //显示音乐播放时长的标签
private ProgressBar pbMusicProgress; //音乐播放进度条
private ListView lvMusicName; //音乐名列表控件
private List<Music> musicList; //音乐列表(数据源)
private MusicAdapter adapter; //音乐适配器
private MusicPlayerApplication app; //音乐播放器应用程序对象
private ProgressBar pbScanMusic; //扫描存储卡音乐进度条
private TextView tvScanMusic; //扫描存储卡音乐标签(提示用户耐心等待)





@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //通过资源标识符获取控件实例
    lvMusicName = findViewById(R.id.lvMusicName);
    tvMusicName = findViewById(R.id.tvMusicName);
    btnP1ayOrPause = 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);

    //获取音乐播放器应用程序对象
    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();

    //给音乐列表控件注册监听器
    lvMusicName.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, 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 FillMusicListTask extends AsyncTask<Void, Integer, Void> {
    /**
     * 耗时工作执行前
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // 显示扫描音乐进度条
        pbScanMusic.setVisibility(View.VISIBLE);
        // 显示扫描音乐标签
        tvScanMusic.setVisibility(View.VISIBLE);
    }

    @Override
    protected Void doInBackground(Void... voids) {
        // 获取音乐列表
        musicList = app.getMusicList();
        // 故意耗时,要不然扫描太快结束
        for (long i = 0; i < 2000000000; i++) {
        }
        return null;
    }

    /**
     * 耗时工作执行后
     *
     * @param aVoid
     */
    @Override
    protected 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, "外置存储卡上没有音乐文件!", Toast.LENGTH_SHORT);
        }
    }
}


/*
 * 音乐广播接收器
 * */

private class MusicReceiver extends BroadcastReceiver {

    @Override
    public 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);
                //设置[播放|暂停]按钮显示的图标
                btnP1ayOrPause.setBackgroundResource(controlIcon);

            }
        }
    }
}

/**
 *上一首音乐按钮单击事件处理方法
 * @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);
}


/**
 *销毁回调方法
 */
@Override
protected void onDestroy() {
    super. onDestroy();
    //停止音乐播放服务
    stopService( new Intent(MainActivity. this, MusicPlayService.class));
    //注销广播接收器
    if (receiver != null) {
        unregisterReceiver( receiver);
    }
}

}
三、运行结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值