该文章主要针对 android 的音乐播放器软件进行简单的功能添加:播放、断点播放、停止、上一曲、下一曲、随机播放、显示当前播放歌曲(后续会为当前显示的播放添加动画);
软件开发流程:
1、先向内存卡导入音乐文件(文件的导入方法可以自己查找,文章类较多);
2、获取内存卡中的音乐文件;
3、将音乐文件存入集合中,便于调用,并将需要播放的文件显示在 ListView 中(点击 ListView 中的文件也可播放);
4、运用 MediaPlayer的方法实现播放、暂停、断点播放、连续播放文件;
5、通过调用写好的方法实现手动的下一曲、上一曲、随机播放、显示当前播放的音乐名;
<pre name="code" class="java">package com.wangban.yzbbanban.v10;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
//声明各个组件,集合
private List<Music> musics;
private ListView lvMusicList;
private ImageButton ibtnPlayOrPause;
private ImageButton ibtnNext;
private ImageButton ibtnprevious;
private ImageButton ibtnGetPosition;
private RadioButton rbtnPlayRandown;
private RadioButton rbtnPlaySequence;
private RadioButton rbtnPlaySingle;
private MusicAdapter adapter;
private TextView tvTip;
private Context context;
//声明 MediaPla
private MediaPlayer player;
// 记录的暂停时的播放位置
private int pausePosition;
// 当前播放的歌曲的索引
private int currentMusicIndex;
@Override
//主函数
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置布局为 activity_main
setContentView(R.layout.activity_main);
//初始化控件
initView();
//获取歌曲列表
loadData();
//列出列表
initListView();
//配置监听器
setListener();
//重置(设置 MediaPlayer必须步骤)
player.reset();
}
//设置各种监听器
private void setListener() {
InnerOnclickListener listener = new InnerOnclickListener();
//暂停播放
ibtnPlayOrPause.setOnClickListener(listener);
//下一首
ibtnNext.setOnClickListener(listener);
//上一首
ibtnprevious.setOnClickListener(listener);
//获取当前播放音乐
ibtnGetPosition.setOnClickListener(listener);
InnerItemOnCLickListener listener2 = new InnerItemOnCLickListener();
//给 ListView 添加点击(点击音乐即可播放)
lvMusicList.setOnItemClickListener(listener2);
// MediaPlay 自动播放(因为就一条,无需加变量)
player.setOnCompletionListener(new InnerOnCompletionListener());
}
//播放ListView 点击的音乐
private class InnerItemOnCLickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//获取点击的列表的中音乐的位置,赋值给当前播放音乐
currentMusicIndex = position;
//令暂停的进度为0(即为从头播放)
pausePosition = 0;
//播放
play();
}
}
//主要按钮的播放监听器
private class InnerOnclickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
// 播放/暂停按钮即执行的方法
case R.id.ibtn_playorpause:
//当音乐在播放时
if (player.isPlaying()) {
//暂停
pause();
} else {
//不在播放,则播放
play();
}
break;
//下一首按钮即执行方法
case R.id.ibtn_next:
next();
break;
//上一首按钮即执行方法
case R.id.ibtn_previous:
previous();
break;
//获取当前播放音乐即执行方法
case R.id.ibtn_getposition:
getPosition();
break;
}
}
}
//单曲循环
private void single() {
currentMusicIndex++;
currentMusicIndex--;
pausePosition = 0;
play();
}
//随机播放方法
private void randown() {
currentMusicIndex = new Random().nextInt(musics.size());
Toast.makeText(MainActivity.this, "随机", Toast.LENGTH_SHORT).show();
pausePosition = 0;
play();
}
//列表循环
private void sequence() {
currentMusicIndex++;
if (currentMusicIndex >= musics.size()) {
currentMusicIndex = 0;
}
pausePosition = 0;
play();
}
//获取当前播放的音乐文件的名字,必先是在另一个布局中;
private void getPosition() {
//声明一个意图,用来切换布局和传递数据
Intent intent = new Intent();
//定义要传递的数据
String extra = musics.get(currentMusicIndex).getName() + "";
//传递数据
intent.putExtra("currentMusic", extra);
//切换布局
intent.setClass(MainActivity.this, Main2Activity.class);
//执行此系列活动
MainActivity.this.startActivity(intent);
}
//暂停
private void pause() {
//直接调用MediaPlay 中的暂停方法
player.pause();
//获取暂停的位置(音乐进度)
pausePosition = player.getCurrentPosition();
//切换为播放的按钮(按钮为android系统自带的按钮,可直接用)
ibtnPlayOrPause.setImageResource(android.R.drawable.ic_media_play);
}
//播放上一曲
private void previous() {
//判断是否为第一首歌曲,若为第一首歌曲,则播放最后一首
if (rbtnPlaySingle.isChecked()) {
single();
} else {
//当前音乐播放位置--(上一曲)
currentMusicIndex--;
if (currentMusicIndex <= 0) {
Toast.makeText(MainActivity.this, "已经是第一首了", Toast.LENGTH_SHORT).show();
return;
} else {
//音乐进度置为0
pausePosition = 0;
//播放
play();
}
}
}
//播放下一曲(与上一曲类似)
private void next() {
if (rbtnPlayRandown.isChecked()) {
randown();
} else if (rbtnPlaySingle.isChecked()) {
single();
} else if (rbtnPlaySequence.isChecked()) {
sequence();
} else {
currentMusicIndex++;
if (currentMusicIndex >= musics.size()) {
Toast.makeText(MainActivity.this, "已经是最后一首了", Toast.LENGTH_SHORT).show();
return;
} else {
pausePosition = 0;
play();
}
}
}
//播放音乐
private void play() {
//重置
player.reset();
try {
//设置音乐文件来源
player.setDataSource(musics.get(currentMusicIndex).getPath());
//准备(缓冲文件)
player.prepare();
//将进度设置到“音乐进度”
player.seekTo(pausePosition);
//获取音乐进度
player.getCurrentPosition();
//播放开始
player.start();
//用当前界面的 TextView显示当前播放的音乐
tvTip.setText(musics.get(currentMusicIndex).getName() + "");
//设置按钮图片为暂停图标
ibtnPlayOrPause.setImageResource(android.R.drawable.ic_media_pause);
} catch (IOException e) {
e.printStackTrace();
}
}
private final class InnerOnCompletionListener implements MediaPlayer.OnCompletionListener {
@Override
public void onCompletion(MediaPlayer mp) {
next();
}
}
private void initListView() {
adapter = new MusicAdapter(getApplicationContext(), musics);
lvMusicList.setAdapter(adapter);
}
private void loadData() {
//获取音乐文件的内容
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
// 获取歌曲列表
musics = new ArrayList<>();
// 1. 检查sdcard是否可用
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// 2. 获取sdcard下Music文件夹的File对象
File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
// 3. 检查Music文件夹是否存在
if (musicDir.exists()) {
// 4. 通过File类的listFiles()方法,获取Music文件夹下所有子级File对象
File[] files = musicDir.listFiles();
// 5. 检查获取到的File列表是否有效(数组是否为null,或数组长度是否为0)
if (files != null && files.length > 0) {
// 6. 遍历File列表
for (int i = 0; i < files.length; i++) {
//下一个文件
cursor.moveToNext();
//获取艺术家内容
String artist = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.ARTIST));
// 6.1. 通过File类的isFile()方法,检查是否是文件
if (files[i].isFile()) {
// 6.2. 通过File类的getName()方法获取文件名,
// 结合String类的endsWith()方法,检查是否是mp3文件
String fileName = files[i].getName();
if (fileName.toUpperCase(Locale.CHINA).endsWith(".MP3")) {
// 6.3. 创建Music对象,并封装必要的属性
Music music = new Music();
music.setName(fileName.substring(0, fileName.length() - 4));
music.setArtist(artist);
music.setPath(files[i].getAbsolutePath());
// 6.4. 将新创建的Music对象添加到集合中
musics.add(music);
}
}
}
}
}
}
}
//初始化控件级布局文件等
private void initView() {
player = new MediaPlayer();
lvMusicList = (ListView) findViewById(R.id.lv_musiclist);
ibtnPlayOrPause = (ImageButton) findViewById(R.id.ibtn_playorpause);
ibtnNext = (ImageButton) findViewById(R.id.ibtn_next);
ibtnprevious = (ImageButton) findViewById(R.id.ibtn_previous);
ibtnGetPosition = (ImageButton) findViewById(R.id.ibtn_getposition);
rbtnPlayRandown = (RadioButton) findViewById(R.id.rbtn_playrandowm);
rbtnPlaySequence = (RadioButton) findViewById(R.id.rbtn_playsequence);
rbtnPlaySingle = (RadioButton) findViewById(R.id.rbtn_playsingle);
tvTip = (TextView) findViewById(R.id.tv_musictip);
context = MainActivity.this;
}
}
<pre name="code" class="java">package com.wangban.yzbbanban.v10;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
//实现显示当前播放的音乐
public class Main2Activity extends AppCompatActivity {
private TextView tvCurrentMusic;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置当前布局为activity_main2
setContentView(R.layout.activity_main2);
//声明 TextView 控件
tvCurrentMusic = (TextView) findViewById(R.id.tv_current_music);
//获取主程序传出的“当前播放文件名字”的值
Intent intent= this.getIntent();
String stringValue=intent.getStringExtra("currentMusic");
tvCurrentMusic.setText(stringValue);
}
}
package com.wangban.yzbbanban.v10;
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 java.util.List;
//集合:显示音乐文件的名称、路径,显示在 ListView 中
public class MusicAdapter extends BaseAdapter{
private Context context;
private List<Music> musics;
public MusicAdapter(Context context, List<Music> musics) {
this.context = context;
this.musics = musics;
}
@Override
public int getCount() {
return musics.size();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//获取当个文件的位置
Music music=musics.get(position);
//将文件布置在模板中
if (convertView==null){
LayoutInflater inflater=LayoutInflater.from(context);
convertView=inflater.inflate(R.layout.music_item,null);
}
//初始化控件
TextView tvName= (TextView) convertView.findViewById(R.id.tv_music_title);
TextView tvArtist= (TextView) convertView.findViewById(R.id.tv_music_path);
//TextView tvPath= (TextView) convertView.findViewById(R.id.tv_music_path);
//显示文件内容
//显示歌曲名
tvName.setText(music.getName());
//tvPath.setText(music.getPath());
//显示艺术家名字
tvArtist.setText(music.getArtist());
return convertView;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
package com.wangban.yzbbanban.v10;
//Music 类型文件,用于集合musics,声明一个类型,获取集合中的名字、路径
public class Music {
//name 类型
private String name;
//path 类型
private String path;
//获取艺术家
private String artist;
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Music{" +
"name='" + name + '\'' +
", path='" + path + '\'' +
'}';
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="当前播放的歌曲:"
android:textSize="20sp"
android:background="@color/colorPrimary"
/>
<ImageView
android:id="@+id/iv_current_player"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:src="@drawable/default_play_activity_bg1" />
<TextView
android:id="@+id/tv_current_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:layout_below="@id/iv_current_player"
android:text="" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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/ic_launcher_app"
android:padding="5dp"
tools:context="com.wangban.yzbbanban.v10.MainActivity">
<RelativeLayout
android:id="@+id/rl_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<ImageButton
android:id="@+id/ibtn_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_media_previous" />
<ImageButton
android:id="@+id/ibtn_playorpause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/ibtn_previous"
android:src="@android:drawable/ic_media_play" />
<ImageButton
android:id="@+id/ibtn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/ibtn_playorpause"
android:src="@android:drawable/ic_media_next" />
<ImageButton
android:id="@+id/ibtn_getposition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="@android:drawable/ic_menu_mylocation"
/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_playstate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_above="@id/rl_music"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/rg_playstate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/rbtn_playsequence"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:background="@drawable/selector_sequence"
android:button="@null" />
<RadioButton
android:id="@+id/rbtn_playrandowm"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_toLeftOf="@id/rbtn_playsequence"
android:background="@drawable/selector_randowm"
android:button="@null" />
<RadioButton
android:id="@+id/rbtn_playsingle"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_toRightOf="@id/rbtn_playsequence"
android:background="@drawable/selector_single"
android:button="@null" />
</RadioGroup>
</RelativeLayout>
<TextView
android:id="@+id/tv_musictip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/rl_playstate"
android:padding="10dp"
android:text="您播放的歌为"
android:textColor="#ffdfce"
android:textSize="17sp" />
<ListView
android:id="@+id/lv_musiclist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/tv_musictip"
/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<ImageView
android:id="@+id/iv_artist"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/ic_luancher_app"
/>
<TextView
android:id="@+id/tv_music_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_artist"
android:text="歌名"
android:textColor="#eeeeee"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_music_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_music_title"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_artist"
android:text="路径"
android:textColor="#999999"
android:textSize="14sp" />
</RelativeLayout>
//随机图标的选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/play_list_mode_shuffle"
></item>
<item android:drawable="@drawable/playmode_repeate_random_hover"></item>
</selector>
//顺序播放的图标的选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/play_list_mode_sequent"
></item>
<item android:drawable="@drawable/playmode_repeate_all_hover"></item>
</selector>
//单曲循环的图标的选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/play_list_mode_repeat_one"
></item>
<item android:drawable="@drawable/playmode_repeate_single_hover"></item>
</selector>