目录
一、引言
Android初学者开发第一个完整的实例项目应该就属《音乐播放器》了,项目包含SQLlit数据库的使用、listview、Fragment、等。话不多说先上成品:
视频效果展示:
Android Studio 音乐播放器
图片效果展示:
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.音乐播放功能
用于播放音乐,对音乐进行暂停,上一首、下一首功能的实现。
具体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文件代码:
来源地址:https://blog.csdn.net/qq_29823791/article/details/130920290