今天学习写一个简易音乐播放器。
首先新建一个项目,命名为MusicPlayer
看项目结构:
ImusicService代码:
package com.glsite.musicplayer;
import java.util.List;
/**
* @author glsite.com
* @version $Rev$
* @des ${TODO}
* @updateAuthor $Author$
* @updateDes ${TODO}
*/
public interface ImusicService {
/**
* 调用服务里面的播放逻辑
*
* 音乐资源路径集合
* @param position
*
*/
public void callPlay(List<String>playList ,int position);
/**
* 调用停止播放的方法
*/
public void callstop();
}
MainActivity代码:
package com.glsite.musicplayer;
import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
public class MainActivity extends BaseActivity {
private ListView mLv;
private ImusicService mImusicService;
//public static final String MP3DIR = Environment.getExternalStorageDirectory()+ "/Download/";
public static final String MP3DIR = Environment.getExternalStorageDirectory()+ "/qqmusic/song/";
private ArrayList<String> mMp3List;
private MyConn mConn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLv = findViewById(R.id.lv);
performCodeWithPermission("读取SD卡需要用到的权限", new PermissionCallback() {
@Override
public void hasPermission() {
//如果有了读取权限,那么初始化播放列表
initPlayList();
}
@Override
public void noPermission() {
}
}, Manifest.permission.READ_EXTERNAL_STORAGE);
Intent intent = new Intent(this, MusicPlayerService.class);
startService(intent);
mConn = new MyConn();
bindService(intent, mConn,BIND_AUTO_CREATE);
mLv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mImusicService != null) {
mImusicService.callPlay(mMp3List,position);
} else {
Toast.makeText(MainActivity.this,"还没有绑定服务吧", Toast.LENGTH_SHORT).show();
}
}
});
}
private class MyConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mImusicService = (ImusicService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/**
* 初始化播放列表
*/
private void initPlayList() {
File file = new File(MP3DIR);
//用这个方法返回列表对象
File[] files = file.listFiles();
//建一个ArrayList来存各个文件名
mMp3List = new ArrayList<>();
//开始遍历
for (File f : files){
if(f.getName().endsWith(".mp3")){
mMp3List.add(f.getAbsolutePath());
System.out.println(f.getAbsoluteFile());
}
}
mLv.setAdapter(new MusicListAdapter());
}
//如果加入菜单就要写相应的方法
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = new MenuInflater(this);
inflater.inflate(R.menu.activity_main,menu);
return super.onCreateOptionsMenu(menu);
}
//这个是菜单选中事件的方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_setting) {
//启动一个设置界面
Intent intent = new Intent(this, SettingActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.item_exit){
//停止播放并退出
playerExit();
}
return super.onOptionsItemSelected(item);
}
/**
* 停止服务并退出
*/
private void playerExit(){
if(mImusicService != null){
mImusicService.callstop();
}
if (mConn != null){
unbindService(mConn);
mConn = null;
}
Intent intent = new Intent(this, MusicPlayerService.class);
stopService(intent);
finish();
}
@Override
protected void onDestroy() {
playerExit();
super.onDestroy();
}
private class MusicListAdapter extends BaseAdapter {
@Override
//列表内歌曲数量
public int getCount() {
return mMp3List.size();
}
//传入当前的对象
@Override
public Object getItem(int position) {
return mMp3List.get(position);
}
//id
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(MainActivity.this, R.layout.item_music, null);
TextView tv_name = (TextView) view.findViewById(R.id.tv_item_name);
String path = mMp3List.get(position);
tv_name.setText(path.substring(path.lastIndexOf("/") + 1));
return view;
}
}
}
MusicPlayerService代码:
package com.glsite.musicplayer;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import java.io.IOException;
import java.util.List;
public class MusicPlayerService extends Service {
public static final int MUSIC_STOP = 0;
public static final int MUSIC_PLAYING = 1;
public static final int MUSIC_PAUSE = 2;
private SharedPreferences mSp;
private MediaPlayer mMediaPlayer;
public static int playingstatus = 0;
public MusicPlayerService() {
}
@Override
public IBinder onBind(Intent intent) {
return new Mybinder();
}
@Override
public void onCreate() {
System.out.println("音乐播放器服务开启了");
mSp = getSharedPreferences("config", MODE_PRIVATE);
mMediaPlayer = new MediaPlayer();
super.onCreate();
}
@Override
public void onDestroy() {
System.out.println("音乐服务播放器关闭了");
super.onDestroy();
}
private class Mybinder extends Binder implements ImusicService{
@Override
public void callPlay(List<String> playList, int position) {
play(playList,position);
}
@Override
public void callstop() {
stopPlayer();
}
}
/**
* 停止播放
*/
private void stopPlayer() {
if(mMediaPlayer != null){
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancelAll();
}
/**
* 播放音乐
* @param playList
* 所有音频播放列表
* @param position
* 当前播放的音频
*/
private void play(final List<String> playList, final int position) {
try {
if(mMediaPlayer.isPlaying()){
mMediaPlayer.stop();
}
mMediaPlayer.reset();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
System.out.println(playList.get(position));
mMediaPlayer.setDataSource(playList.get(position));
mMediaPlayer.prepare();
mMediaPlayer.start();
String path = playList.get(position);
showNotification(path.substring(path.lastIndexOf("/") + 1));
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
int mode = mSp.getInt("mode", 0);
if (mode == SettingActivity.CYCLE) {
play(playList,position);
} else if (mode == SettingActivity.NEXT){
//播放下一曲
int newposition = position+1;
if(newposition>playList.size()){
newposition = 0;
}
play(playList,newposition);
}else if (mode == SettingActivity.STOP){
//设置状态为停止
playingstatus = MUSIC_STOP;
}
}
});
} catch (Exception e) {
e.printStackTrace();
playingstatus = MUSIC_STOP;
}
}
/**
* 显示播放器的音乐通知提醒
* @param filename
* 音乐名
*/
private void showNotification(String filename) {
int importance = NotificationManager.IMPORTANCE_LOW;
//判断如果当前的sdk版本>=8.0
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
String id = "channel_1";
NotificationChannel channel = new NotificationChannel(id, "123", importance);
Notification noti = new Notification.Builder(this,id).setContentTitle("酷狗音乐正在播放")
.setContentText(filename)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round))
.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.createNotificationChannel(channel);
nm.notify(0,noti);
}
//判断如果当前的sdk版本<8.0
else{
Notification noti = new Notification.Builder(this).setContentTitle("酷狗音乐正在播放")
.setContentText(filename)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round))
.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(0,noti);
}
}
}
SettingActivity代码:
package com.glsite.musicplayer;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class SettingActivity extends AppCompatActivity {
public static final int CYCLE = 1;
public static final int NEXT = 2;
public static final int STOP = 3;
private RadioGroup mRgMode;
private SharedPreferences mSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
mRgMode = findViewById(R.id.rg_mode);
mSp = getSharedPreferences("config", MODE_PRIVATE);
//使用这个方法可以在下一次打开时保持上次离开时的状态,你懂吧
//你想想看,如果不使用sp文件,那么点击返回会直接将当前activity结束,到时候返回值就是空
int mode = mSp.getInt("mode", 0);
RadioButton rb;
switch (mode) {
case CYCLE:
rb = findViewById(R.id.rb_cycle);
rb.setChecked(true);
break;
case NEXT:
rb = findViewById(R.id.rb_next);
rb.setChecked(true);
break;
case STOP:
rb = findViewById(R.id.rb_stop);
rb.setChecked(true);
break;
default:
break;
}
mRgMode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
SharedPreferences.Editor editor = mSp.edit();
switch (checkedId) {
case R.id.rb_cycle:
editor.putInt("mode",CYCLE);
break;
case R.id.rb_next:
editor.putInt("mode",NEXT);
break;
case R.id.rb_stop:
editor.putInt("mode",STOP);
break;
default:
break;
}
editor.commit();
}
});
}
}
layout下activi_main代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</android.support.constraint.ConstraintLayout>
activity_setting代码:
<?xml version="1.0" encoding="utf-8"?>
<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=".SettingActivity"
android:orientation="vertical">
<RadioGroup
android:id="@+id/rg_mode"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/rb_cycle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="单曲循环" />
<RadioButton
android:id="@+id/rb_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="下一曲" />
<RadioButton
android:id="@+id/rb_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="播放后停止" />
</RadioGroup>
</LinearLayout>
item_music代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginLeft="5dp"
android:text="歌曲名称"
android:textColor="#99ff0000"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textSize="20sp"/>
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:layout_centerVertical="true"
app:srcCompat="@mipmap/ic_launcher" />
</RelativeLayout>
menu下activity_main代码:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/item_setting"
android:title="设置界面"/>
<item android:id="@+id/item_exit"
android:title="关闭播放器"/>
</menu>