Android Studio 实现音乐播放器
🍅文章末尾有获取完整项目源码方式🍅
一、引言
Android初学者开发第一个完整的实例项目应该就属《音乐播放器》了,项目包含SQLlit数据库的使用、listview、Fragment、等。话不多说先上成品:
视频效果展示:
Android studio期末设计大作业~音乐播放器App
图片效果展示:
1.启动页效果 |

2.登录页效果 |

3.注册页效果 |

4.歌曲列表页效果 |

5.播放页效果 |

二、详细设计
1.登陆注册功能
用户进行注册数据使用SQLite存储,用户登录时根据数据库的内容来核对用户名和密码是否正确。


Login.xml代码:
Register.xml代码:
LoginActivity完整代码:
package com.example.music.Login;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.music.MainActivity;
import com.example.music.R;
import com.example.music.Register.RegisterActivity;
import com.example.music.Data.DatabaseHelper;
public class LoginActivity extends AppCompatActivity {
private TextView loginRegister;
private EditText user;
private EditText pass;
private Button mLoginButton;
private DatabaseHelper mDatabaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
user = findViewById(R.id.user);
pass = findViewById(R.id.pass);
mLoginButton = findViewById(R.id.login_button);
loginRegister = findViewById(R.id.login_register);
mDatabaseHelper = new DatabaseHelper(this);
loginRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
}
});
mLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = user.getText().toString().trim();
String password = pass.getText().toString().trim();
if (username.isEmpty() || password.isEmpty()) {
Toast.makeText(getApplicationContext(), "请输入账号或密码", Toast.LENGTH_SHORT).show();
return;
}
boolean result = mDatabaseHelper.checkUser(username, password);
if (result) {
Toast.makeText(getApplicationContext(), "登陆成功", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "账号或密码错误", Toast.LENGTH_SHORT).show();
}
}
});
}
}
RegisterActivity完整代码:
package com.example.music.Register;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.music.Login.LoginActivity;
import com.example.music.R;
import com.example.music.Data.DatabaseHelper;
public class RegisterActivity extends AppCompatActivity {
private EditText mUserNameEditText;
private EditText mPasswordEditText;
private Button registerButton;
private DatabaseHelper mDatabaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
mUserNameEditText = findViewById(R.id.username_edittext);
mPasswordEditText = findViewById(R.id.password_edittext);
registerButton = findViewById(R.id.register_button);
mDatabaseHelper = new DatabaseHelper(this);
registerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = mUserNameEditText.getText().toString().trim();
String password = mPasswordEditText.getText().toString().trim();
if (username.isEmpty() || password.isEmpty()) {
Toast.makeText(getApplicationContext(), "请输入账号或密码", Toast.LENGTH_SHORT).show();
return;
}
boolean result = mDatabaseHelper.insertData(username, password);
if (result) {
Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
startActivity(intent);
finish();
} else {
Toast.makeText(getApplicationContext(), "注册失败", Toast.LENGTH_SHORT).show();
}
}
});
}
}
2.音乐列表页面
主要用于音乐的显示以及点击对应的音乐跳转到对应的音乐播放页面。

Activity完整代码:
package com.example.music;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.example.music.Music.MusicActivity;
public class SongPage extends Fragment {
//声明视图变量view
private View view;
//在这里添加歌曲名
public String[] songname = {"Innocence", "刚刚好","不用去猜"};
private String[] name={"A R L","薛之谦","Jony J"};
//在这里添加歌曲图片
public static int[] icons = {R.drawable.img_01, R.drawable.img_02, R.drawable.img_03};
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.music_list, null);
//1、创建并绑定列表
ListView listView = view.findViewById(R.id.lv);
//2、创建适配器对象
MyBaseAdapter adapter = new MyBaseAdapter();
//3、给列表设置适配器
listView.setAdapter(adapter);
//设置列表条目监听器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
//创建Intent对象,启动音乐播放界面
Intent intent = new Intent(SongPage.this.getContext(), MusicActivity.class);
//将数据存入Intent对象,利用键值对
intent.putExtra("name", name[position]);
intent.putExtra("songname", songname[position]);
intent.putExtra("position", String.valueOf(position));
//开启意图,进行跳转
startActivity(intent);
}
});
return view;
}
class MyBaseAdapter extends BaseAdapter {
@Override
public int getCount() {
return name.length;
}
@Override
public Object getItem(int i) {
return name[i];
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View convertView, ViewGroup parent) {
//绑定视图,并且显示歌曲名和歌曲图片
View view = View.inflate(SongPage.this.getContext(), R.layout.item_music, null);
TextView songName = view.findViewById(R.id.song_name);
ImageView songPic = view.findViewById(R.id.song_pic);
TextView name1=view.findViewById(R.id.name);
songName.setText(songname[i]);
name1.setText(name[i]);
songPic.setImageResource(icons[i]);
return view;
}
}
}
相关的xml代码:
2.音乐播放功能
用于播放音乐,对音乐进行暂停,上一首、下一首功能的实现。

该类是一个音乐播放器的活动,包含了播放、暂停、继续播放、上一首、下一首、退出等功能。以下是该类的一些关键点:
成员变量:
musicName:存储歌曲名称的字符串数组。
sb:进度条 SeekBar 对象。
tv_progress、tv_total、name_song:显示播放进度、总时长和歌曲名的 TextView 对象。
animator:旋转动画对象,用于旋转歌手图片框。
musicControl:音乐控制类的对象。
初始化方法 initView():
初始化各个控件,并设置点击事件监听器。
创建意图对象 intent2,并创建 MyServiceConn 服务连接对象 conn。
绑定服务,将音乐控制类的对象 musicControl 与服务绑定。
消息处理器 handler:
用于在主线程中处理从子线程发送过来的消息。
处理音乐播放进度的更新,通过更新进度条和显示当前播放时长和总时长。
服务连接类 MyServiceConn:
实现 ServiceConnection 接口,用于连接服务。
在 onServiceConnected() 方法中获取音乐控制类的对象。
在 onServiceDisconnected() 方法中处理服务断开连接的情况。
onClick() 方法:
处理按钮的点击事件,根据点击的按钮执行相应的操作,如播放、暂停、继续播放、上一首、下一首、退出等。
在点击播放按钮时,隐藏播放按钮,开始播放音乐,并启动旋转动画。
在点击暂停按钮时,隐藏暂停按钮,显示继续播放按钮,并暂停音乐播放和旋转动画。
在点击继续播放按钮时,隐藏继续播放按钮,显示暂停按钮,并继续音乐播放和旋转动画。
在点击上一首按钮时,切换到上一首歌曲,并更新歌手图片和歌曲名。
在点击下一首按钮时,切换到下一首歌曲,并更新歌手图片和歌曲名。
在点击退出按钮时,解除服务绑定并关闭活动。
onDestroy() 方法:
在活动销毁时解除服务绑定。
具体MusicActivity代码:
public class MusicActivity extends AppCompatActivity implements View.OnClickListener{
//定义歌曲名称的数组
public String[] musicName={"Innocence", "刚刚好","不用去猜"};
private static SeekBar sb;//定义进度条
private static TextView tv_progress, tv_total, name_song;//定义开始和总时长,歌曲名控件
private ObjectAnimator animator;//定义旋转的动画
private MusicService.MusicControl musicControl;//音乐控制类
private Button play; //播放按钮
private Button pause; //暂停按钮
private Button con; //继续播放按钮
private Button pre; //上一首按钮
private Button next; //下一首按钮
private ImageView exit; //退出按钮
private ImageView iv_music; //歌手图片框
Intent intent1, intent2; //定义两个意图
MyServiceConn conn; //服务连接
private boolean isUnbind = false;//记录服务是否被解绑
public int change = 0; //记录下标的变化值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
//去除标题栏
ActionBar actionBar = getSupportActionBar();
if(actionBar!= null){
actionBar.hide();
}
//获得意图
intent1 = getIntent();
//初始化
initView();
}
//初始化
private void initView(){
//依次绑定控件
tv_progress = findViewById(R.id.tv_progress);
tv_total = findViewById(R.id.tv_total);
sb = findViewById(R.id.sb);
name_song = findViewById(R.id.song_name);
iv_music = findViewById(R.id.iv_music);
play = findViewById(R.id.btn_play);
pause = findViewById(R.id.btn_pause);
con = findViewById(R.id.btn_continue_play);
pre = findViewById(R.id.btn_pre);
next = findViewById(R.id.btn_next);
exit = findViewById(R.id.btn_exit);
//依次设置监听器
play.setOnClickListener(this);
pause.setOnClickListener(this);
con.setOnClickListener(this);
pre.setOnClickListener(this);
next.setOnClickListener(this);
exit.setOnClickListener(this);
//创建意图对象
intent2 = new Intent(this, MusicService.class);
conn = new MyServiceConn();//创建服务连接对象
bindService(intent2, conn,BIND_AUTO_CREATE);//绑定服务
//从歌曲列表传过来的歌曲名
String name = intent1.getStringExtra("songname");
//设置歌曲名显示
name_song.setText(name);
//定义歌曲列表传过来的下标position
String position = intent1.getStringExtra("position");
//将字符串转化为整型i
int i = parseInt(position);
//图像框设置为frag1里面的图标数组,下标为i
iv_music.setImageResource(SongPage.icons[i]);
//为滑动条添加事件监听
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//当滑动条到末端时,将message对象发送出去
if (progress == sb.getMax()){
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {//滑动条开始滑动时调用
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {//滑动条停止滑动时调用
//根据拖动的进度改变音乐播放进度
int progress = seekBar.getProgress();//获取seekBar的进度
musicControl.seekTo(progress);//改变播放进度
}
});
animator= ObjectAnimator.ofFloat(iv_music,"rotation",0f,360.0f);
animator.setDuration(10000);//动画旋转一周的时间为10秒
animator.setInterpolator(new LinearInterpolator());//匀速
animator.setRepeatCount(-1);//-1表示设置动画无限循环
}
//歌曲进度条的消息机制
public static Handler handler = new Handler(){//创建消息处理器对象
//在主线程中处理从子线程发送过来的消息
@Override
public void handleMessage(Message msg){
Bundle bundle = msg.getData();//获取从子线程发送过来的音乐播放进度
int duration = bundle.getInt("duration");
int currentPosition = bundle.getInt("currentPosition");
sb.setMax(duration);
sb.setProgress(currentPosition);
//歌曲总时长,单位为毫秒
int minute = duration/1000/60;
int second = duration/1000%60;
String strMinute = null;
String strSecond = null;
if(minute < 10){//如果歌曲的时间中的分钟小于10
strMinute = "0" + minute;//在分钟的前面加一个0
}else{
strMinute = minute + "";
}
if (second < 10){//如果歌曲中的秒钟小于10
strSecond = "0" + second;//在秒钟前面加一个0
}else{
strSecond = second + "";
}
tv_total.setText(strMinute + ":" + strSecond);
//歌曲当前播放时长
minute = currentPosition/1000/60;
second = currentPosition/1000%60;
if(minute < 10){//如果歌曲的时间中的分钟小于10
strMinute = "0" + minute;//在分钟的前面加一个0
}else{
strMinute=minute + " ";
}
if (second < 10){//如果歌曲中的秒钟小于10
strSecond = "0" + second;//在秒钟前面加一个0
}else{
strSecond = second + " ";
}
tv_progress.setText(strMinute + ":" + strSecond);
}
};
//用于实现连接服务
class MyServiceConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service){
musicControl=(MusicService.MusicControl) service;
}
@Override
public void onServiceDisconnected(ComponentName name){
}
}
//未解绑则解绑
private void unbind(boolean isUnbind){
if(!isUnbind){//判断服务是否被解绑
musicControl.pausePlay();//暂停播放音乐
unbindService(conn);//解绑服务
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onClick(View v) {
//获取歌曲名的下标字符串
String index = intent1.getStringExtra("position");
//将字符串转为整数
int i = parseInt(index);
switch (v.getId()){
case R.id.btn_play://播放按钮点击事件
play.setVisibility(View.INVISIBLE);
musicControl.play(i);
animator.start();
break;
//这里musicName.length-1表示的最后一首歌的下标,即歌曲总数-1
case R.id.btn_pre://播放上一首
if((i + change) < 1) {
change = musicName.length - 1 - i;
iv_music.setImageResource(SongPage.icons[i + change]);
name_song.setText(musicName[i + change]);
musicControl.play(i + change);
pause.setVisibility(View.VISIBLE);
animator.start();
break;
} else {
change--;
iv_music.setImageResource(SongPage.icons[i + change]);
name_song.setText(musicName[i + change]);
musicControl.play(i + change);
pause.setVisibility(View.VISIBLE);
animator.start();
break;
}
case R.id.btn_next://播放下一首
if((i + change) == musicName.length - 1) {
change = -i;
iv_music.setImageResource(SongPage.icons[i + change]);
name_song.setText(musicName[i + change]);
musicControl.play(i + change);
pause.setVisibility(View.VISIBLE);
animator.start();
break;
} else {
change++;
iv_music.setImageResource(SongPage.icons[i + change]);
name_song.setText(musicName[i + change]);
musicControl.play(i + change);
pause.setVisibility(View.VISIBLE);
animator.start();
break;
}
case R.id.btn_pause://暂停按钮点击事件
pause.setVisibility(View.INVISIBLE);
con.setVisibility(View.VISIBLE);
musicControl.pausePlay();
animator.pause();
break;
case R.id.btn_continue_play://继续播放按钮点击事件
con.setVisibility(View.INVISIBLE);
pause.setVisibility(View.VISIBLE);
musicControl.continuePlay();
animator.start();
break;
case R.id.btn_exit://退出按钮点击事件
unbind(isUnbind);
isUnbind = true;
finish();
break;
}
}
@Override
protected void onDestroy(){
super.onDestroy();
unbind(isUnbind);//解绑服务
}
}
相关的xml文件代码:
三、获取源码
关注公众号《编程乐学》,后台回复:23031701
👇👇👇快捷获取方式👇👇👇
本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/9ca90b1982.html
