使用MediaPlayer+Service+Broadcast完成音乐播放器
其中有添加了随机顺序和单曲
1.先把歌曲封装成一个类
public class Music {
public static final int MODE_SIGNEL=0;//单曲的常量值
public static final int MODE_ORDER=1;//顺序的常量值
public static final int MODE_RANDOM=2;//随机的常量值
private String title;
private String artist;
private String duration;
private String data;
private String size;
public Music() {
}
public Music(String title, String artist, String duration, String data, String size) {
this.title = title;
this.artist = artist;
this.duration = duration;
this.data = data;
this.size = size;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
@Override
public String toString() {
return "Music{" +
"title='" + title + '\'' +
", artist='" + artist + '\'' +
", duration='" + duration + '\'' +
", data='" + data + '\'' +
", size='" + size + '\'' +
'}';
}
}
2.封装查询本地歌曲的工具类
public class MusicUtil {
public static List<Music> getMusic(Context context) {
ArrayList<Music> music = new ArrayList<>();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
String size = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE));
Music music1 = new Music(title, artist, duration, data, size);
music.add(music1) ;
Toast.makeText(context,music+"",Toast.LENGTH_SHORT).show();
}
}
return music;
}
}
//格式化时间
public static String formatTime(int time) {
if (time / 1000 % 60 < 10) {
return time / 1000 / 60 + ":0" + time / 1000 % 60;
} else {
return time / 1000 / 60 + ":" + time / 1000 % 60;
}
}
}
3 .封装一个adapter类
public class MyAdapter extends BaseAdapter {
private List<Music>list;
private Context context;
public MyAdapter(List<Music> list, Context context) {
this.list = list;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView==null) {
convertView = LayoutInflater.from(context).inflate(R.layout.layout, null);
viewHolder = new ViewHolder();
viewHolder.title = convertView.findViewById(R.id.titleTextview);
viewHolder.artist = convertView.findViewById(R.id.artist);
viewHolder.duration = convertView.findViewById(R.id.data);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.title.setText(list.get(position).getTitle()+"");
viewHolder.artist.setText(list.get(position).getArtist()+"");
int data = Integer.parseInt(list.get(position).getDuration());
String s = MusicUtils.formaTime(data);
viewHolder.duration.setText(s);
return convertView;
}
class ViewHolder{
TextView title;
TextView artist;
TextView duration;
}
4.adapter中的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textview1"
android:layout_width="149dp"
android:layout_height="30dp"
android:hint="歌名"></TextView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal">
<TextView
android:id="@+id/textview2"
android:layout_width="216dp"
android:layout_height="match_parent"
android:hint="歌手" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="right">
<TextView
android:id="@+id/textview3"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:hint="时长"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
5.服务中的所有代码
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
private List<Music>list;
int index;
private Notification.Builder builder;
private int playmode = Music.MODE_ORDER;
public MusicService() {
}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
list = MusicUtils.getMusic(this);
}
public class MusicBinder extends Binder{
public void callPlay(int position){
playMusic(position);
index = position;
}
public void callPause(){
pause();
}
public void callPlayNextMuic(){
next();
}
public void callPlayNavMusic(){
top();
}
public void callMode(int mode){
playMode(mode);
}
private void playMode(int mode) {
switch (mode){
case Music.MODE_SIGNEL:
playmode = Music.MODE_SIGNEL;
break;
case Music.MODE_ORDER:
playmode = Music.MODE_ORDER;
break;
case Music.MODE_RANDOM:
playmode = Music.MODE_RANDOM;
break;
}
}
private void top(){
index--;
if (index<0){
index = list.size()-1;
}
playMusic(index);
}
public void callRestart(){
restart();
}
public void callseek(int progress){
seek(progress);
}
private void seek(int progress) {
mediaPlayer.seekTo(progress);
}
}
//继续
private void restart() {
mediaPlayer.start();
}
//暂停
private void pause() {
if (mediaPlayer.isPlaying()){
mediaPlayer.pause();
}
}
private void playMusic(int position) {
if (mediaPlayer.isPlaying()){
mediaPlayer.start();
}
mediaPlayer.reset();
Music music = list.get(position);
try {
mediaPlayer.setDataSource(music.getData());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
Message obtain = Message.obtain();
obtain.what=888;
obtain.arg1=mediaPlayer.getCurrentPosition();
MainActivity.handler.sendMessage(obtain);
}
},0,1000);
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mode(playmode);
}
private void mode(int mode) {
switch (mode){
case Music.MODE_SIGNEL:
mediaPlayer.setLooping(true);
playMusic(index);
playmode = Music.MODE_SIGNEL;
break;
case Music.MODE_ORDER:
next();
playmode = Music.MODE_ORDER;
break;
case Music.MODE_RANDOM:
int i = new Random().nextInt(list.size());
playMusic(i);
index=i;
playmode = Music.MODE_RANDOM;
break;
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
private void next() {
index++;
if (index>list.size()-1){
index=0;
}
playMusic(index);
}
@Override
public IBinder onBind(Intent intent) {
return new MusicBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout2);
Intent intent1 = new Intent();
intent1.setAction("com.music.pause");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 800, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.pause,pendingIntent);
Intent intent2 = new Intent();
intent2.setAction("com.music.restart");
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(this, 810, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.restart,pendingIntent2);
Intent intent3 = new Intent();
intent3.setAction("com.music.top");
PendingIntent pendingIntent3 = PendingIntent.getBroadcast(this, 820, intent3, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.top,pendingIntent3);
Intent intent4 = new Intent();
intent4.setAction("com.music.down");
PendingIntent pendingIntent4 = PendingIntent.getBroadcast(this, 830, intent4, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.down,pendingIntent4);
builder.setCustomContentView(remoteViews);
startForeground(1,builder.build());
return super.onStartCommand(intent, flags, startId);
}
}
6 .service中通知的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停"
android:id="@+id/pause"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="继续"
android:id="@+id/restart"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上一首"
android:id="@+id/top"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一首"
android:id="@+id/down"/>
</LinearLayout>
7.广播的内容
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("com.music.pause")){
MainActivity.handler.sendEmptyMessage(110);
}else if (action.equals("com.music.restart")){
MainActivity.handler.sendEmptyMessage(120);
}else if (action.equals("com.music.top")){
MainActivity.handler.sendEmptyMessage(130);
}else if (action.equals("com.music.down")){
MainActivity.handler.sendEmptyMessage(140);
}
}
}
8.MainActivity中的代码
public class MainActivity extends AppCompatActivity {
private ListView listview;//ListView
private Button pause;//暂停按钮
private Button restart;//继续
private Button top;//上一首
private Button down;//下一首
private Button lalala;//随机切换
public static int playmode=0;//随机切换用到的常量值
private List<Music>list;
private static MusicService.MusicBinder binder;
private ServiceConnection serviceConnection;
private static SeekBar seekBar;
public static Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//更新进度条
if (msg.what==888){
seekBar.setProgress(msg.arg1);
}
//通知中,按钮的实现
if (msg.what==110){
binder.callPause();
}else if (msg.what==120){
binder.callRestart();
}else if (msg.what==130){
binder.callPlayNavMusic();
}else if (msg.what==140){
binder.callPlayNextMuic();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview = (ListView) findViewById(R.id.listview);
pause = (Button) findViewById(R.id.pause);
restart = (Button) findViewById(R.id.restart);
top = (Button) findViewById(R.id.top);
down = (Button) findViewById(R.id.down);
seekBar = findViewById(R.id.seekBar);
lalala = findViewById(R.id.lalala);
lalala.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int i = playmode%3;
binder.callMode(i);
playmode++;
switch (i){
case Music.MODE_SIGNEL:
lalala.setText("单曲");
break;
case Music.MODE_ORDER:
lalala.setText("顺序");
break;
case Music.MODE_RANDOM:
lalala.setText("随机");
break;
}
}
});
//通知中的动态注册
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.music.pause");
intentFilter.addAction("com.music.restart");
intentFilter.addAction("com.music.top");
intentFilter.addAction("com.music.down");
MyReceiver myReceiver = new MyReceiver();
registerReceiver(myReceiver,intentFilter);
//动态添加权限
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
//Activity暂停
pause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
binder.callPause();
}
});
// Activity继续
restart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
binder.callRestart();
}
});
// Activity上一首
top.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
binder.callPlayNavMusic();
}
});
// Activity下一首
down.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
binder.callPlayNextMuic();
}
});
}
//读取手机内存的权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode==100&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
start();
}
}
private void start() {
list= MusicUtils.getMusic(MainActivity.this);
MyAdapter myAdapter = new MyAdapter(list,this);
listview.setAdapter(myAdapter);
//点击listview条目播放音乐 进度条
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
binder.callPlay(position);
//设置进度条最大值为歌曲的时长
seekBar.setMax(Integer.parseInt(list.get(position).getDuration()));
}
});
//进度条更改监听
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser){
binder.callseek(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
Intent intent = new Intent(this, MusicService.class);
startService(intent);
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MusicService.MusicBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
}
}
9.MainActivity中的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="11"
android:id="@+id/listview"></ListView>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/seekBar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="暂停"
android:id="@+id/pause"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="继续"
android:id="@+id/restart"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="上一首"
android:id="@+id/top"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="下一首"
android:id="@+id/down"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="顺序"
android:id="@+id/lalala"/>
</LinearLayout>
</LinearLayout>
10.清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.day019">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".Receive.MyReceiver"
android:enabled="true"
android:exported="true">
</receiver>
<service
android:name=".Service.MusicService"
android:enabled="true"
android:exported="true" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>