Android Studio 实现音乐播放器
目录
一、引言
视频效果展示:
1.启动页效果
2.登录页效果
3.注册页效果
4.歌曲列表页效果
5.播放页效果
二、详细设计
1.登陆注册功能
2.音乐列表页面
2.音乐播放功能
三、源码获取
一、引言
Android初学者开发第一个完整的实例项目应该就属《音乐播放器》了,项目包含SQLlit数据库的使用、listview、Fragment、等。话不多说先上成品:
视频效果展示:
Android Studio 音乐播放器
图片效果展示:
1.启动页效果 |
2.登录页效果 |
3.注册页效果 |
4.歌曲列表页效果 |
5.播放页效果 |
二、详细设计
1.登陆注册功能
用户进行注册数据使用SQLite存储,用户登录时根据数据库的内容来核对用户名和密码是否正确。
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.音乐列表页面
主要用于音乐的显示以及点击对应的音乐跳转到对应的音乐播放页面。
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.音乐播放功能
用于播放音乐,对音乐进行暂停,上一首、下一首功能的实现。
具体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 实现音乐播放器
目录 一、引言 视频效果展示: 1.启动页效果 2.登录页效果 3.注册页效果 4.歌曲列表页效果 5.播放页效果 二、详细设计 1.登陆注册功能 2.音乐列表页面 2.音乐播放功能 三、源码获取 一、引言 Android初学者开发第一个完整的实例项目应该就属《音乐播放器…...
端口占用命令 netstat (centos)+netstat (windows)
linux 1.使用 netstat 命令查看端口占用情况 netstat -tlnp 使用 -p 选项查看进程信息。 使用 -t 选项列出 TCP 协议的连接:类似(使用 -u 选项列出 UDP 协议的连接:) 2.查找占用指定端口号的应用信息 netstat -tlnp | grep 3…...
Python-基于fastapi实现SSE流式返回(类似GPT)
最近在做大模型对话相关功能,需要将对话内容流式返回给前端页面(类似GPT的效果)。下面直接说下如何实现: 1.首先导入fastapi和sse流式返回所需要的包 from fastapi import APIRouter, Response, status from sse_starlette.sse …...
iOS中宿主APP与录屏扩展进程数据传递方式
背景 在iOS生态系统中,应用程序的功能不再局限于单一的宿主应用,而是可以通过扩展进程实现更丰富的用户体验和功能。其中一种引人注目的扩展是录屏功能,它使用户能够捕捉设备屏幕上的活动,无论是游戏过程、教育演示还是其他应用场…...
Windows系统下的可用RADIUS软件-[资源]
RADIUS协议相关原理介绍,可参考博客RADIUS协议原理介绍报文分析配置指导-RFC2865/RFC2866。 本文用于提供和介绍Window系统下几种可用的RADIUS软件。主要涉及软件有radius_ping(绿色免安装版)和WinRadius(绿色免安装版)…...
基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十五:基础数据模块相关功能实现
一、本章内容 本章使用已实现的公共组件实现系统管理中的基础数据中的验证码管理、消息管理等功能。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址: 基于VUE3+Layui从头搭建通用后台管理系统合集-验证码功能实现 3.2 西瓜…...
MAC苹果笔记本电脑如何彻底清理垃圾文件软件?
苹果电脑以其流畅的操作系统和卓越的性能而备受用户喜爱。然而,随着时间的推移,系统可能会积累大量垃圾文件,影响性能。本文将介绍苹果电脑怎么清理垃圾文件的各种方法,以提升系统运行效率。 CleanMyMac X是一款专业的Mac清理软件…...
【Linux C | 文件I/O】文件的打开关闭 | open、creat、colse 函数
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
【BEV感知】BEVFormer 融合多视角图形的空间特征和时序特征 ECCV 2022
前言 本文分享BEV感知方案中,具有代表性的方法:BEVFormer。 它基于Deformable Attention,实现了一种融合多视角相机空间特征和时序特征的端到端框架,适用于多种自动驾驶感知任务。 主要由3个关键模块组成: BEV Que…...
Amazon Toolkit — CodeWhisperer 使用
tFragment--> 官网:https://aws.amazon.com/cn/codewhisperer/?trkcndc-detail 最近学习了亚马逊云科技的 代码工具,感慨颇多。下面是安装 和使用的分享。 CodeWhisperer,亚马逊推出的实时 AI 编程助手,是一项基于机器学习…...
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是一款高性能、分布式的对象存储系统,它可以100%的运行在标准硬件上,即X86等…...
通过https协议访问Tomcat部署并使用Shiro认证的应用跳转登到录页时协议变为http的问题
问题描述: 在最近的一个项目中,有一个存在较久,并且只在内部城域网可访问的一个使用Shiro框架进行安全管理的Java应用,该应用部署在Tomcat服务器上。起初,应用程序可以通过HTTP协议访问,一切运行都没…...
Backend - Django 项目创建 运行
目录 一、配置环境 二、创建 Django 项目 (一)新建文件夹 (二)打开文件夹 (三)打开运行终端 (四)创建基础项目 (五)创建app 1. 安装Django …...
C# .Net学习笔记—— Expression 表达式目录树
一、什么是表达式目录树 (1)Expression我们称为是表达式树,是一种数据结构体,用于存储需要计算,运算的一种结构,这种结构可以只是存储,而不进行运算。通常表达式目录树是配合Lambda一起来使用的…...
《论文阅读28》Unsupervised 3D Shape Completion through GAN Inversion
GAN,全称GenerativeAdversarialNetworks,中文叫生成式对抗网络。顾名思义GAN分为两个模块,生成网络以及判别网络,其中 生成网络负责根据随机向量产生图片、语音等内容,产生的内容是数据集中没有见过的,也可…...
一个正则快速找到在ES中使用profile的时产生慢查询的分片
在es中使用profile分析慢查询的时候,往往因为分片过多,或者因为查询条件太复杂,分析的结果几十万行。在kibana上点半天,也找不到一个耗时长的分片。 kibana上可以通过正则来匹配。其实我们只需要匹配到耗时大于10秒的请求。 检索语…...
链接未来:深入理解链表数据结构(一.c语言实现无头单向非循环链表)
在上一篇文章中,我们探索了顺序表这一基础的数据结构,它提供了一种有序存储数据的方法,使得数据的访 问和操作变得更加高效。想要进一步了解,大家可以移步于上一篇文章:探索顺序表:数据结构中的秩序之美 今…...
Python tkinter控件全集之组合选择框 ttk.ComboBox
Tkinter标准库 Tkinter是Python的标准GUI库,也是最常用的Python GUI库之一,提供了丰富的组件和功能,包括窗口、按钮、标签、文本框、列表框、滚动条、画布、菜单等,方便开发者进行图形界面的开发。Tkinter库基于Tk for Unix/Wind…...
Axure之中继器的使用(交互动作reperter属性Item属性)
目录 一.中继器的基本使用 二.中继器的动作(增删改查) 2.1 新增 2.2 删除 2.3 更新行 2.4 效果展示 2.5 模糊查询 三.reperter属性 在Axure中,中继器(Repeater)是一种功能强大的组件,用于创建重复…...
数字化医疗新篇章:构建智能医保支付购药系统
在迎接数字化医疗时代的挑战和机遇中,智能医保支付购药系统的建设显得尤为重要。本文将深入介绍如何通过先进的技术实现,构建一套智能、高效的医保支付购药系统,为全面建设健康中国贡献力量。 1. 引言 随着医疗科技的飞速发展,…...
11_12-Golang中的运算符
**Golang **中的运算符 主讲教师:(大地) 合作网站:www.itying.com** **(IT 营) 我的专栏:https://www.itying.com/category-79-b0.html 1、Golang 内置的运算符 算术运算符关系运算符逻辑运…...
k8s-ingress特性 9
TLS加密 创建证书 测试访问 auth认证 创建认证文件 rewrite重定向 进入域名时,会自动重定向到hostname.html 示例: 测试 版本的升级迭代,之前利用控制器进行滚动更新,在升级过程中无法做到快速回滚 更加平滑的升级࿱…...
【redis】redis系统实现发布订阅的标准模板
目录 简介参数配置代码模板 简介 Redis发布订阅功能是Redis的一种消息传递模式,允许多个客户端之间通过消息通道进行实时的消息传递。在发布订阅模式下,消息的发送者被称为发布者(publisher),而接收消息的客户端被称为…...
Python 时间日期处理库函数
标准库 datetime >>> import datetime >>> date datetime.date(2023, 12, 20) >>> print(date) 2023-12-20 >>> date datetime.datetime(2023, 12, 20) >>> print(date) 2023-12-20 00:00:00 >>> print(date.strfti…...
第二十二章 : Spring Boot 集成定时任务(一)
第二十二章 : Spring Boot 集成定时任务(一) 前言 本章知识点: 介绍使用Spring Boot内置的Scheduled注解来实现定时任务-单线程和多线程;以及介绍Quartz定时任务调度框架:简单定时调度器(Simp…...
关于“Python”的核心知识点整理大全32
目录 12.6.4 调整飞船的速度 settings.py ship.py alien_invasion.py 12.6.5 限制飞船的活动范围 ship.py 12.6.6 重构 check_events() game_functions.py 12.7 简单回顾 12.7.1 alien_invasion.py 12.7.2 settings.py 12.7.3 game_functions.py 12.7.4 ship.py …...
【krita】实时绘画 入门到精通 海报+电商+装修+人物
安装插件 首先打开comfyUI,再打开krita,出现问题提示, 打开 cd custom_nodes 输入命令 安装控件 git clone https://github.com/Acly/comfyui-tooling-nodes.git krita基础设置 设置模型 设置lora (可设置lora强度 增加更多…...
云原生系列2-CICD持续集成部署-GitLab和Jenkins
1、CICD持续集成部署 传统软件开发流程: 1、项目经理分配模块开发任务给开发人员(项目经理-开发) 2、每个模块单独开发完毕(开发),单元测试(测试) 3、开发完毕后,集成部…...
50ms时延工业相机
华睿工业相机A3504CG000 参数配置: 相机端到端理论时延:80ms 厂家同步信息,此款设备帧率上线23fps,单帧时延:43.48ms,按照一图缓存加上传输显示的话,厂家预估时延在:80ms 厂家还有…...
上海高端室内设计事务所/seo排名查询软件
插件的安装如下:1.下载插件包https://github.com/vim-scripts/Pydiction可以直接下载,也可git下载[rootlocalhost]# git clone https://github.com/rkulla/pydiction.git#####################包括三个文件python_pydiction.vim #vim插件complete-di…...
天津网站建设业务/广州网站建设公司
1)Chromely Chromely 是一个轻量级的类似 Electron.NET的框架,服务于 .NET/.NET Core 开发者 https://github.com/chromelyapps/Chromely...
WordPress书籍插件/上首页seo
硬盘是用来存储数据的,为了使用和管理方便,这些数据以文件的形式存储在硬盘上。任何操作系统都有自己的文件管理系统,不同的文件系统又有各自不同的逻辑组织方式。例如:常见的文件系统有FAT,NTFS,EXT&#…...
wordpress恢复小工具/seo关键词排名优化教程
Python模块化编程 包 模块 模块是一个包含所有你定义的函数和变量的文件,其后缀为.py(就如我们编写的程序就是一个模块),可被其他程序引入。以使用该模块的函数等功能 模块分为三种: 1.内置模块:sys,os,sub…...
网站空间期限查询/友情链接qq群
文章目录一、配置数据源-mysql二、下载安装1.1 下载包安装(已验证)1.2 Github 上下载源码(未验证)1.3 docker安装(已验证)三、springCloud pom主要配置3.1 pom3.2 bootstrap.yaml部分配置3.3 nacos设置对应一、配置数据源-mysql a:配置数据库 /*Navicat Premium Data Transfe…...
北京通州区网站制作/网站新站整站排名
本文章是一篇IDEA创建web项目配置Tomcat的整合文章,并非原创,原文链接https://blog.csdn.net/qq_45738810/article/details/107842532https://www.cnblogs.com/shindo/p/7272646.html作为初学者,先看了第一个链接里大佬的文章又看其他的文章表…...