当前位置: 首页 > news >正文

Android Studio 实现音乐播放器

目录

一、引言

视频效果展示:

1.启动页效果

2.登录页效果

3.注册页效果

4.歌曲列表页效果

5.播放页效果

 二、详细设计

1.登陆注册功能

2.音乐列表页面

2.音乐播放功能

三、源码获取


一、引言

        Android初学者开发第一个完整的实例项目应该就属《音乐播放器》了,项目包含SQLlit数据库的使用、listview、Fragment、等。话不多说先上成品:

视频效果展示:

Android Studio 音乐播放器

图片效果展示:

1.启动页效果

bdf383c204b04df8b20d3bf52630e838.png

2.登录页效果

62bad85a5697492faceb78a9ff260663.png

3.注册页效果

6954222d65b34b1494711fbf043aad89.png

4.歌曲列表页效果

f2343f9f53de4f429827d30fd9f0deb1.png

5.播放页效果

26cbc5b2ae874f3c879dc9304d1dd6fa.png

 二、详细设计

1.登陆注册功能

        用户进行注册数据使用SQLite存储,用户登录时根据数据库的内容来核对用户名和密码是否正确。

fb5231b97ce541b284fb99d7988388c8.pngf1e5f1ad2a484436bf50efb9910dca80.png

 Login.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"android:background="#f9d7e7"tools:context=".Login.LoginActivity"><ImageViewandroid:id="@+id/imageView3"android:layout_width="200dp"android:layout_height="150dp"android:layout_marginTop="24dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/logo1" /><Viewandroid:id="@+id/view2"android:layout_width="0dp"android:layout_height="320dp"android:layout_marginTop="24dp"android:background="@drawable/login_view"app:layout_constraintEnd_toStartOf="@+id/guideline2"app:layout_constraintStart_toStartOf="@+id/guideline3"app:layout_constraintTop_toBottomOf="@+id/imageView3" /><Buttonandroid:id="@+id/login_button"android:layout_width="250dp"android:layout_height="55dp"android:layout_marginBottom="32dp"android:background="@drawable/login"android:text="立 即 登 录 "android:textColor="#fff"android:textSize="24sp"app:layout_constraintBottom_toBottomOf="@+id/view2"app:layout_constraintEnd_toStartOf="@+id/guideline2"app:layout_constraintStart_toStartOf="@+id/view2" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.9" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.1" /><Viewandroid:id="@+id/view3"android:layout_width="0dp"android:layout_height="45dp"android:layout_marginTop="40dp"android:background="@drawable/login_count"app:layout_constraintEnd_toEndOf="@+id/login_button"app:layout_constraintStart_toStartOf="@+id/login_button"app:layout_constraintTop_toTopOf="@+id/view2" /><Viewandroid:id="@+id/view4"android:layout_width="0dp"android:layout_height="45dp"android:layout_marginTop="24dp"android:background="@drawable/login_count"app:layout_constraintEnd_toEndOf="@+id/login_button"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="@+id/login_button"app:layout_constraintTop_toBottomOf="@+id/view3" /><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="24dp"android:text="忘 记 密 码"app:layout_constraintStart_toStartOf="@+id/view4"app:layout_constraintTop_toBottomOf="@+id/view4" /><TextViewandroid:id="@+id/login_register"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="立 即 注 册"app:layout_constraintBottom_toBottomOf="@+id/textView"app:layout_constraintEnd_toEndOf="@+id/view4"app:layout_constraintTop_toTopOf="@+id/textView" /><ImageViewandroid:id="@+id/imageView"android:layout_width="20dp"android:layout_height="20dp"app:layout_constraintBottom_toBottomOf="@+id/view4"app:layout_constraintEnd_toEndOf="@+id/imageView4"app:layout_constraintTop_toTopOf="@+id/view4"app:srcCompat="@drawable/mima" /><ImageViewandroid:id="@+id/imageView4"android:layout_width="20dp"android:layout_height="20dp"android:layout_marginStart="16dp"app:layout_constraintBottom_toBottomOf="@+id/view3"app:layout_constraintStart_toStartOf="@+id/view3"app:layout_constraintTop_toTopOf="@+id/view3"app:srcCompat="@drawable/zhanghao" /><Viewandroid:id="@+id/view5"android:layout_width="100dp"android:layout_height="1dp"android:layout_marginTop="40dp"android:background="#fff"app:layout_constraintStart_toStartOf="@+id/guideline3"app:layout_constraintTop_toBottomOf="@+id/view2" /><Viewandroid:id="@+id/view6"android:layout_width="100dp"android:layout_height="1dp"android:background="#fff"app:layout_constraintEnd_toStartOf="@+id/guideline2"app:layout_constraintTop_toTopOf="@+id/view5" /><TextViewandroid:id="@+id/textView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="其它方式登陆"android:textColor="#fff"app:layout_constraintBottom_toBottomOf="@+id/view5"app:layout_constraintEnd_toStartOf="@+id/view6"app:layout_constraintStart_toEndOf="@+id/view5"app:layout_constraintTop_toTopOf="@+id/view5" /><ImageViewandroid:id="@+id/imageView6"android:layout_width="30dp"android:layout_height="30dp"app:layout_constraintBottom_toBottomOf="@+id/imageView5"app:layout_constraintEnd_toStartOf="@+id/imageView7"app:layout_constraintStart_toEndOf="@+id/imageView5"app:layout_constraintTop_toTopOf="@+id/imageView5"app:srcCompat="@drawable/qq" /><ImageViewandroid:id="@+id/imageView5"android:layout_width="30dp"android:layout_height="30dp"android:layout_marginStart="70dp"android:layout_marginTop="24dp"app:layout_constraintStart_toStartOf="@+id/guideline3"app:layout_constraintTop_toBottomOf="@+id/view5"app:srcCompat="@drawable/weixin" /><ImageViewandroid:id="@+id/imageView7"android:layout_width="30dp"android:layout_height="30dp"android:layout_marginEnd="70dp"app:layout_constraintBottom_toBottomOf="@+id/imageView6"app:layout_constraintEnd_toStartOf="@+id/guideline2"app:layout_constraintTop_toTopOf="@+id/imageView6"app:srcCompat="@drawable/weibo" /><EditTextandroid:id="@+id/user"android:layout_width="190dp"android:layout_height="0dp"android:layout_marginStart="5dp"android:ems="10"android:background="#eff4f2"android:inputType="textPersonName"android:hint="请输入账号"app:layout_constraintBottom_toBottomOf="@+id/view3"app:layout_constraintStart_toEndOf="@+id/imageView4"app:layout_constraintTop_toTopOf="@+id/view3" /><EditTextandroid:id="@+id/pass"android:layout_width="190dp"android:layout_height="0dp"android:layout_marginStart="5dp"android:ems="10"android:background="#eff4f2"android:inputType="textPassword"android:hint="请输入密码"app:layout_constraintBottom_toBottomOf="@+id/view4"app:layout_constraintStart_toEndOf="@+id/imageView"app:layout_constraintTop_toTopOf="@+id/view4"app:layout_constraintVertical_bias="0.0" /></androidx.constraintlayout.widget.ConstraintLayout>

Register.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"android:background="#f9d7e7"tools:context=".Register.RegisterActivity"><ImageViewandroid:id="@+id/imageView3"android:layout_width="200dp"android:layout_height="150dp"android:layout_marginTop="40dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/logo1" /><Viewandroid:id="@+id/view2"android:layout_width="0dp"android:layout_height="270dp"android:background="@drawable/login_view"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/guideline4"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="@+id/guideline"app:layout_constraintTop_toTopOf="@+id/imageView3"app:layout_constraintVertical_bias="0.501" /><Viewandroid:id="@+id/view3"android:layout_width="250dp"android:layout_height="45dp"android:layout_marginTop="32dp"android:background="@drawable/login_count"app:layout_constraintEnd_toStartOf="@+id/guideline4"app:layout_constraintStart_toStartOf="@+id/view2"app:layout_constraintTop_toTopOf="@+id/view2" /><Viewandroid:id="@+id/view4"android:layout_width="0dp"android:layout_height="45dp"android:layout_marginTop="32dp"android:background="@drawable/login_count"app:layout_constraintEnd_toEndOf="@+id/view3"app:layout_constraintStart_toStartOf="@+id/view3"app:layout_constraintTop_toBottomOf="@+id/view3" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.1" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.9" /><ImageViewandroid:id="@+id/imageView"android:layout_width="20dp"android:layout_height="20dp"android:layout_marginStart="8dp"app:layout_constraintBottom_toBottomOf="@+id/view3"app:layout_constraintStart_toStartOf="@+id/view3"app:layout_constraintTop_toTopOf="@+id/view3"app:srcCompat="@drawable/mima" /><ImageViewandroid:id="@+id/imageView4"android:layout_width="20dp"android:layout_height="20dp"app:layout_constraintBottom_toBottomOf="@+id/view4"app:layout_constraintStart_toStartOf="@+id/imageView"app:layout_constraintTop_toTopOf="@+id/view4"app:srcCompat="@drawable/zhanghao" /><Buttonandroid:id="@+id/register_button"android:layout_width="250dp"android:layout_height="55dp"android:text="立 即 注 册"android:layout_marginBottom="32dp"android:background="@drawable/login"app:layout_constraintBottom_toBottomOf="@+id/view2"app:layout_constraintEnd_toEndOf="@+id/view2"app:layout_constraintHorizontal_bias="0.497"app:layout_constraintStart_toStartOf="@+id/view2" /><EditTextandroid:id="@+id/username_edittext"android:layout_width="190dp"android:layout_height="0dp"android:layout_marginStart="5dp"android:ems="10"android:hint="请输入账号"android:background="#eff4f2"android:inputType="textPersonName"app:layout_constraintBottom_toBottomOf="@+id/view3"app:layout_constraintStart_toEndOf="@+id/imageView"app:layout_constraintTop_toTopOf="@+id/view3" /><EditTextandroid:id="@+id/password_edittext"android:layout_width="190dp"android:layout_height="0dp"android:layout_marginStart="5dp"android:ems="10"android:hint="请输入密码"android:background="#eff4f2"android:inputType="textPassword"app:layout_constraintBottom_toBottomOf="@+id/view4"app:layout_constraintStart_toEndOf="@+id/imageView4"app:layout_constraintTop_toTopOf="@+id/view4" /></androidx.constraintlayout.widget.ConstraintLayout>

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;@Overrideprotected 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() {@Overridepublic void onClick(View v) {Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);startActivity(intent);}});mLoginButton.setOnClickListener(new View.OnClickListener() {@Overridepublic 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;@Overrideprotected 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() {@Overridepublic 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.音乐列表页面

         主要用于音乐的显示以及点击对应的音乐跳转到对应的音乐播放页面。

e0090aaa5285487fa8dae5ce3598c456.png

 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 {//声明视图变量viewprivate 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};@Overridepublic 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() {@Overridepublic 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 {@Overridepublic int getCount() {return name.length;}@Overridepublic Object getItem(int i) {return name[i];}@Overridepublic long getItemId(int i) {return i;}@Overridepublic 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代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content"android:padding="15dp"><ImageViewandroid:id="@+id/song_pic"android:layout_width="86dp"android:layout_height="86dp"android:src="@drawable/img_01"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/song_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginTop="16dp"android:text="歌曲"android:textColor="#000"android:textSize="20sp"app:layout_constraintStart_toEndOf="@+id/song_pic"app:layout_constraintTop_toTopOf="@+id/song_pic" /><TextViewandroid:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:text="歌曲"android:textColor="#000"android:textSize="14sp"app:layout_constraintStart_toStartOf="@+id/song_name"app:layout_constraintTop_toBottomOf="@+id/song_name" /><ImageViewandroid:id="@+id/song_enter"android:layout_width="30dp"android:layout_height="30dp"android:layout_marginEnd="8dp"android:src="@drawable/song_play"app:layout_constraintBottom_toBottomOf="@+id/song_pic"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="@+id/song_pic" /></androidx.constraintlayout.widget.ConstraintLayout>

2.音乐播放功能

       用于播放音乐,对音乐进行暂停,上一首、下一首功能的实现。

c63266c89937447b82b5f69ce6c802a9.png

 具体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;      //记录下标的变化值@Overrideprotected 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);//定义歌曲列表传过来的下标positionString position = intent1.getStringExtra("position");//将字符串转化为整型iint i = parseInt(position);//图像框设置为frag1里面的图标数组,下标为iiv_music.setImageResource(SongPage.icons[i]);//为滑动条添加事件监听sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {//当滑动条到末端时,将message对象发送出去if (progress == sb.getMax()){}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//滑动条开始滑动时调用}@Overridepublic 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(){//创建消息处理器对象//在主线程中处理从子线程发送过来的消息@Overridepublic 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){//如果歌曲的时间中的分钟小于10strMinute = "0" + minute;//在分钟的前面加一个0}else{strMinute = minute + "";}if (second < 10){//如果歌曲中的秒钟小于10strSecond = "0" + second;//在秒钟前面加一个0}else{strSecond = second + "";}tv_total.setText(strMinute + ":" + strSecond);//歌曲当前播放时长minute = currentPosition/1000/60;second = currentPosition/1000%60;if(minute < 10){//如果歌曲的时间中的分钟小于10strMinute = "0" + minute;//在分钟的前面加一个0}else{strMinute=minute + " ";}if (second < 10){//如果歌曲中的秒钟小于10strSecond = "0" + second;//在秒钟前面加一个0}else{strSecond = second + " ";}tv_progress.setText(strMinute + ":" + strSecond);}};//用于实现连接服务class MyServiceConn implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service){musicControl=(MusicService.MusicControl) service;}@Overridepublic void onServiceDisconnected(ComponentName name){}}//未解绑则解绑private void unbind(boolean isUnbind){if(!isUnbind){//判断服务是否被解绑musicControl.pausePlay();//暂停播放音乐unbindService(conn);//解绑服务}}@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic 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表示的最后一首歌的下标,即歌曲总数-1case 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;}}@Overrideprotected void onDestroy(){super.onDestroy();unbind(isUnbind);//解绑服务}
}

相关的xml文件代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"android:background="#f9d7e7"android:orientation="vertical"tools:context=".Music.MusicActivity"><ImageViewandroid:id="@+id/btn_exit"android:layout_width="20dp"android:layout_height="20dp"android:layout_marginStart="16dp"android:layout_marginTop="24dp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/back" /><TextViewandroid:id="@+id/song_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="光年之外"android:textColor="#000"android:textSize="24sp"app:layout_constraintBottom_toBottomOf="@+id/btn_exit"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="@+id/btn_exit" /><ImageViewandroid:id="@+id/iv_music"android:layout_width="250dp"android:layout_height="250dp"android:layout_marginTop="80dp"android:src="@drawable/img_01"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btn_exit" /><SeekBarandroid:id="@+id/sb"android:layout_width="250dp"android:layout_height="20dp"android:layout_marginTop="80dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/iv_music" /><TextViewandroid:id="@+id/tv_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginEnd="5dp"android:text="00:00"app:layout_constraintBottom_toBottomOf="@+id/sb"app:layout_constraintEnd_toStartOf="@+id/sb"app:layout_constraintTop_toTopOf="@+id/sb" /><TextViewandroid:id="@+id/tv_total"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="5dp"android:text="00:00"app:layout_constraintBottom_toBottomOf="@+id/sb"app:layout_constraintStart_toEndOf="@+id/sb"app:layout_constraintTop_toTopOf="@+id/sb" /><Buttonandroid:id="@+id/btn_continue_play"android:layout_width="60dp"android:layout_height="60dp"android:background="@drawable/play"app:layout_constraintBottom_toBottomOf="@+id/btn_pre"app:layout_constraintEnd_toStartOf="@+id/btn_next"app:layout_constraintStart_toEndOf="@+id/btn_pre"app:layout_constraintTop_toTopOf="@+id/btn_pre" /><Buttonandroid:id="@+id/btn_pause"android:layout_width="60dp"android:layout_height="60dp"android:background="@drawable/pause"app:layout_constraintBottom_toBottomOf="@+id/btn_next"app:layout_constraintEnd_toStartOf="@+id/btn_next"app:layout_constraintStart_toEndOf="@+id/btn_pre"app:layout_constraintTop_toTopOf="@+id/btn_next" /><Buttonandroid:id="@+id/btn_pre"android:layout_width="40dp"android:layout_height="40dp"android:layout_marginStart="24dp"android:background="@drawable/pre"app:layout_constraintBottom_toBottomOf="@+id/btn_next"app:layout_constraintStart_toStartOf="@+id/tv_progress"app:layout_constraintTop_toTopOf="@+id/btn_next" /><Buttonandroid:id="@+id/btn_next"android:layout_width="40dp"android:layout_height="40dp"android:layout_marginTop="100dp"android:layout_marginEnd="24dp"android:background="@drawable/next"app:layout_constraintEnd_toEndOf="@+id/tv_total"app:layout_constraintTop_toBottomOf="@+id/tv_total" /><Buttonandroid:id="@+id/btn_play"android:layout_width="60dp"android:layout_height="60dp"android:background="@drawable/play"app:layout_constraintBottom_toBottomOf="@+id/btn_pre"app:layout_constraintEnd_toStartOf="@+id/btn_next"app:layout_constraintStart_toEndOf="@+id/btn_pre"app:layout_constraintTop_toTopOf="@+id/btn_pre" /></androidx.constraintlayout.widget.ConstraintLayout>

三、源码获取

✨还可以关注我的公众号《编程乐学》,菜单栏,有很多优质的资料等你来学习。

相关文章:

Android Studio 实现音乐播放器

目录 一、引言 视频效果展示&#xff1a; 1.启动页效果 2.登录页效果 3.注册页效果 4.歌曲列表页效果 5.播放页效果 二、详细设计 1.登陆注册功能 2.音乐列表页面 2.音乐播放功能 三、源码获取 一、引言 Android初学者开发第一个完整的实例项目应该就属《音乐播放器…...

端口占用命令 netstat (centos)+netstat (windows)

linux 1.使用 netstat 命令查看端口占用情况 netstat -tlnp 使用 -p 选项查看进程信息。 使用 -t 选项列出 TCP 协议的连接&#xff1a;类似&#xff08;使用 -u 选项列出 UDP 协议的连接&#xff1a;&#xff09; 2.查找占用指定端口号的应用信息 netstat -tlnp | grep 3…...

Python-基于fastapi实现SSE流式返回(类似GPT)

最近在做大模型对话相关功能&#xff0c;需要将对话内容流式返回给前端页面&#xff08;类似GPT的效果&#xff09;。下面直接说下如何实现&#xff1a; 1.首先导入fastapi和sse流式返回所需要的包 from fastapi import APIRouter, Response, status from sse_starlette.sse …...

iOS中宿主APP与录屏扩展进程数据传递方式

背景 在iOS生态系统中&#xff0c;应用程序的功能不再局限于单一的宿主应用&#xff0c;而是可以通过扩展进程实现更丰富的用户体验和功能。其中一种引人注目的扩展是录屏功能&#xff0c;它使用户能够捕捉设备屏幕上的活动&#xff0c;无论是游戏过程、教育演示还是其他应用场…...

Windows系统下的可用RADIUS软件-[资源]

RADIUS协议相关原理介绍&#xff0c;可参考博客RADIUS协议原理介绍报文分析配置指导-RFC2865/RFC2866。 本文用于提供和介绍Window系统下几种可用的RADIUS软件。主要涉及软件有radius_ping&#xff08;绿色免安装版&#xff09;和WinRadius&#xff08;绿色免安装版&#xff09…...

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十五:基础数据模块相关功能实现

一、本章内容 本章使用已实现的公共组件实现系统管理中的基础数据中的验证码管理、消息管理等功能。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址: 基于VUE3+Layui从头搭建通用后台管理系统合集-验证码功能实现 3.2 西瓜…...

MAC苹果笔记本电脑如何彻底清理垃圾文件软件?

苹果电脑以其流畅的操作系统和卓越的性能而备受用户喜爱。然而&#xff0c;随着时间的推移&#xff0c;系统可能会积累大量垃圾文件&#xff0c;影响性能。本文将介绍苹果电脑怎么清理垃圾文件的各种方法&#xff0c;以提升系统运行效率。 CleanMyMac X是一款专业的Mac清理软件…...

【Linux C | 文件I/O】文件的打开关闭 | open、creat、colse 函数

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

【BEV感知】BEVFormer 融合多视角图形的空间特征和时序特征 ECCV 2022

前言 本文分享BEV感知方案中&#xff0c;具有代表性的方法&#xff1a;BEVFormer。 它基于Deformable Attention&#xff0c;实现了一种融合多视角相机空间特征和时序特征的端到端框架&#xff0c;适用于多种自动驾驶感知任务。 主要由3个关键模块组成&#xff1a; BEV Que…...

Amazon Toolkit — CodeWhisperer 使用

tFragment--> 官网&#xff1a;https://aws.amazon.com/cn/codewhisperer/?trkcndc-detail 最近学习了亚马逊云科技的 代码工具&#xff0c;感慨颇多。下面是安装 和使用的分享。 CodeWhisperer&#xff0c;亚马逊推出的实时 AI 编程助手&#xff0c;是一项基于机器学习…...

Flink SQL填坑记2:Flink和MySQL的Bigdata类型不同导致ClassCastException报错

最近在开发Flink SQL的时候,需要关联Kafka事实表和MySQL维表,得到的数据写入Phoenix表中,但是其中有个字段,Kafka表、MySQL表和Phoenix表都是BigData类型,但是在实现的时候却报“java.math.BigInteger cannot be cast to java.lang.Long”异常,从报错信息来看,是由于Big…...

本地MinIO存储服务如何创建Buckets并实现公网访问上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统&#xff0c;它可以100%的运行在标准硬件上&#xff0c;即X86等…...

通过https协议访问Tomcat部署并使用Shiro认证的应用跳转登到录页时协议变为http的问题

问题描述&#xff1a; 在最近的一个项目中&#xff0c;有一个存在较久&#xff0c;并且只在内部城域网可访问的一个使用Shiro框架进行安全管理的Java应用&#xff0c;该应用部署在Tomcat服务器上。起初&#xff0c;应用程序可以通过HTTP协议访问&#xff0c;一切运行都没…...

Backend - Django 项目创建 运行

目录 一、配置环境 二、创建 Django 项目 &#xff08;一&#xff09;新建文件夹 &#xff08;二&#xff09;打开文件夹 &#xff08;三&#xff09;打开运行终端 &#xff08;四&#xff09;创建基础项目 &#xff08;五&#xff09;创建app 1. 安装Django &#xf…...

C# .Net学习笔记—— Expression 表达式目录树

一、什么是表达式目录树 &#xff08;1&#xff09;Expression我们称为是表达式树&#xff0c;是一种数据结构体&#xff0c;用于存储需要计算&#xff0c;运算的一种结构&#xff0c;这种结构可以只是存储&#xff0c;而不进行运算。通常表达式目录树是配合Lambda一起来使用的…...

《论文阅读28》Unsupervised 3D Shape Completion through GAN Inversion

GAN&#xff0c;全称GenerativeAdversarialNetworks&#xff0c;中文叫生成式对抗网络。顾名思义GAN分为两个模块&#xff0c;生成网络以及判别网络&#xff0c;其中 生成网络负责根据随机向量产生图片、语音等内容&#xff0c;产生的内容是数据集中没有见过的&#xff0c;也可…...

一个正则快速找到在ES中使用profile的时产生慢查询的分片

在es中使用profile分析慢查询的时候&#xff0c;往往因为分片过多&#xff0c;或者因为查询条件太复杂&#xff0c;分析的结果几十万行。在kibana上点半天&#xff0c;也找不到一个耗时长的分片。 kibana上可以通过正则来匹配。其实我们只需要匹配到耗时大于10秒的请求。 检索语…...

链接未来:深入理解链表数据结构(一.c语言实现无头单向非循环链表)

在上一篇文章中&#xff0c;我们探索了顺序表这一基础的数据结构&#xff0c;它提供了一种有序存储数据的方法&#xff0c;使得数据的访 问和操作变得更加高效。想要进一步了解&#xff0c;大家可以移步于上一篇文章&#xff1a;探索顺序表&#xff1a;数据结构中的秩序之美 今…...

Python tkinter控件全集之组合选择框 ttk.ComboBox

Tkinter标准库 Tkinter是Python的标准GUI库&#xff0c;也是最常用的Python GUI库之一&#xff0c;提供了丰富的组件和功能&#xff0c;包括窗口、按钮、标签、文本框、列表框、滚动条、画布、菜单等&#xff0c;方便开发者进行图形界面的开发。Tkinter库基于Tk for Unix/Wind…...

Axure之中继器的使用(交互动作reperter属性Item属性)

目录 一.中继器的基本使用 二.中继器的动作&#xff08;增删改查&#xff09; 2.1 新增 2.2 删除 2.3 更新行 2.4 效果展示 2.5 模糊查询 三.reperter属性 在Axure中&#xff0c;中继器&#xff08;Repeater&#xff09;是一种功能强大的组件&#xff0c;用于创建重复…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践&#xff0c;很多人以为AI已经强大到不需要程序员了&#xff0c;其实不是&#xff0c;AI更加需要程序员&#xff0c;普通人…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

【动态规划】B4336 [中山市赛 2023] 永别|普及+

B4336 [中山市赛 2023] 永别 题目描述 你做了一个梦&#xff0c;梦里有一个字符串&#xff0c;这个字符串无论正着读还是倒着读都是一样的&#xff0c;例如&#xff1a; a b c b a \tt abcba abcba 就符合这个条件。 但是你醒来时不记得梦中的字符串是什么&#xff0c;只记得…...