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">

    <ImageView
        android: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" />

    <View
        android: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" />

    <Button
        android: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.Guideline
        android: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.Guideline
        android:id="@+id/guideline3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.1" />

    <View
        android: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" />

    <View
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <ImageView
        android: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" />

    <ImageView
        android: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" />

    <View
        android: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" />

    <View
        android: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" />

    <TextView
        android: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" />

    <ImageView
        android: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" />

    <ImageView
        android: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" />

    <ImageView
        android: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" />

    <EditText
        android: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" />

    <EditText
        android: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">

    <ImageView
        android: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" />

    <View
        android: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" />

    <View
        android: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" />

    <View
        android: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.Guideline
        android: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.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.9" />

    <ImageView
        android: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" />

    <ImageView
        android: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" />

    <Button
        android: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" />

    <EditText
        android: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" />

    <EditText
        android: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;

    @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.音乐列表页面

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

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 {
    //声明视图变量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代码:

<?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">

    <ImageView
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <ImageView
        android: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;      //记录下标的变化值
    @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文件代码:

<?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">

    <ImageView
        android: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" />

    <TextView
        android: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" />

    <ImageView
        android: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" />

    <SeekBar
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <Button
        android: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" />

    <Button
        android: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" />

    <Button
        android: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" />

    <Button
        android: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" />

    <Button
        android: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>

三、源码获取

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/243376.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis:一、面试题常见分类+缓存穿透的定义、解决方案、布隆过滤器的原理和误判现象、面试回答模板

redis面试题常见分类 缓存穿透 定义 缓存穿透是一种现象&#xff0c;引发这种现象的原因大概率是遭到了恶意攻击。具体就是查询一个一定不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致这个数据的每次请求都需要查DB&#xff0c;数据库压力…

简洁应用框架VSEF的架构

本文介绍了一些简洁架构VSEF的一些框架结构理解&#xff0c;并且抛出了一些演化的主题&#xff0c;这些主题的不同思考会让系统发展成不同的风格&#xff0c;实际也是应用定位的必然结果。 总体 VSEF 架构理念 基本结构 演化 基本结构 入口 内核 依赖内核 简单逻辑 复杂…

「Leetcode」滑动窗口—长度最小的子数组

&#x1f4bb;文章目录 &#x1f4c4;题目✏️题目解析 & 思路&#x1f4d3;总结 &#x1f4c4;题目 209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, …,…

小航助学2023年9月电子学会Scratch四级真题(含题库答题软件账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 单选题3.00分 删除编辑附件图文 答案:A 第1题角色为一个紫色圆圈&#xff0c;运行程序后&#xff0c;舞台上的图案是&#xff1f;&#xff08; &#xff09; A…

Android 动画 Lottie 如何使用

Android 动画 Lottie 如何使用 一、简介 Lottie 是Airbnb开源的一个面向 iOS、Android、React Native 的动画库&#xff0c;能分析 Adobe After Effects 导出的动画&#xff0c;并且能让原生 App 像使用静态素材一样使用这些动画&#xff0c;完美实现动画效果。 二、Lottie动…

RRC下的NAS层

无线资源控制&#xff08;Radio Resource Control&#xff0c;RRC&#xff09;&#xff0c;又称为无线资源管理&#xff08;RRM&#xff09;或者无线资源分配&#xff08;RRA&#xff09;&#xff0c;是指通过一定的策略和手段进行无线资源管理、控制和调度&#xff0c;在满足服…

12.13_黑马数据结构与算法笔记Java

目录 098 堆 heapify 3 099 堆 增删替换 100 堆 e01 堆排序 100 堆e02 求数组第k大元素 100 堆e03 求数据流第k大元素 100 堆e04 求数据流中位数1 100 堆e04 求数据流中位数2 100 堆e04 求数据流中位数3 101 二叉树 概述 102 二叉树 深度优先遍历 103 二叉树 前中后…

人工智能导论习题集(2)

第三章&#xff1a;确定性推理 题1题2题3题4题5题6 题1 题2 题3 题4 题5 题6

Docker容器:docker推送镜像至Harbor

目录 1、Harbor创建项目 2、进入test项目&#xff0c;查看推送命令 3、在docker服务器上准备一个镜像 4、修改docker客户端配置 5、重启docker服务 6、docker登录Harbor 7、docker镜像推送到Harbor 1、Harbor创建项目 2、进入test项目&#xff0c;查看推送命令 3、在dock…

薅github的羊毛-用pages建自己的博客或资源站 - 博客工具 - 2/2

笔者调研了好多个静态博客工具&#xff0c;最后锁定Hexo了&#xff0c;但不等于其他博客不行。我只吐槽两个 Hugo - 难用Gridea - 简直就是骗钱的&#xff0c;我交钱用不了 theme没有链接&#xff0c;同步也同步不了&#xff0c;估计以前是可以&#xff0c;现在经营不下去&…

JUC并发编程 04——Java内存模型之JMM

一.CPU 缓存模型 为什么要弄一个 CPU 高速缓存呢&#xff1f; 类比我们开发网站后台系统使用的缓存&#xff08;比如 Redis&#xff09;是为了解决程序处理速度和访问常规关系型数据库速度不对等的问题。 CPU 缓存则是为了解决 CPU 处理速度和内存处理速度不对等的问题。 我们…

MDK 生成二进制bin文件 设置 任意路径

第一步&#xff1a;找到魔法&#xff0c; 第二步&#xff1a;拷贝语法到Run#1 : fromelf.exe --bin -o "$LL.bin" "#L" 第三步&#xff1a;点击Ok 第四步&#xff1a;重新编译即可生成bin文件

自炫锁2-b

1. 自旋锁 自旋锁也是为实现保护共享资源而提出一种锁机制。其实&#xff0c;自旋锁与互斥锁比较类似&#xff0c;它们都是为了解决对某项资源的互斥使用。 无论是互斥锁&#xff0c;还是自旋锁&#xff0c;在任何时刻&#xff0c;最多只能有一个保持者&#xff0c;也就说&…

CGAL的3D网格生成

1、介绍 该软件包致力于生成离散三维域的各向同性简化网格。要网格化的域是三维空间的子集&#xff0c;需要有界。域可以连接或由多个组件组成和/或细分为几个子域。 边界曲面和细分曲面是平滑曲面或分段平滑曲面&#xff0c;由平面或曲面面片形成。表面可能表现出一维特征&…

TCP/IP详解——ARP 协议

文章目录 一、ARP 协议1. ARP 数据包格式2. ARP 工作过程3. ARP 缓存4. ARP 请求5. ARP 响应6. ARP 代理7. ARP 探测IP冲突8. ARP 协议抓包分析9. ARP 断网攻击10. 总结 一、ARP 协议 ARP&#xff08;Address Resolution Protocol&#xff09;协议工作在网络层和数据链路层之间…

浅谈 USB Bulk 深入浅出 (3) - USB Bulk 装置传输的注意事项

来源&#xff1a;大大通 作者&#xff1a;冷氣團 1 USB Bulk 是什么 USB 是即插即用使用差动信号的装置界面&#xff0c;是以 端点 ( Endpoint )&#xff0c;做为传输装置的输出入端&#xff0c;透过不同的端点 ( Endpoint ) 和模式&#xff0c;来进行与装置的沟通&#xff…

WWW 指南-万维网联盟(World Wide Web)

WWW - 万维网联盟 WWW通常称为网络。 web是一个世界各地的计算机网络。 电脑在Web上使用标准语言沟通。 万维网联盟&#xff08;W3C&#xff09;制定了Web标准 什么是WWW&#xff1f; WWW 代表 World Wide Web(万维网)万维网常常被称为 网络网络是世界各地的计算机网络网络中…

nestjs守卫/全局守卫校验jwt

一、守卫 目标 部分接口需要用户登录后才可以访问&#xff0c;用户登录后可以颁发 jwt_token 给前端&#xff0c;前端在调用需要鉴权的接口&#xff0c;需要在请求头添加 jwt_token&#xff0c;后端校验通过才能继续访问&#xff0c;否则返回403无权访问 创建守卫 anth 安装…

java.lang.NegativeArraySizeException

构建maven项目时发生的异常 maven-resources-production:gci-system-start:java.lang.NegativeArraySizeException:-1972174848解决方案 先将 target 目录删除,然后重新构建项目即可

【从零开始学习JVM | 第九篇】了解 常见垃圾回收器

前言&#xff1a; 垃圾回收器&#xff08;Garbage Collector&#xff09;是现代编程语言中的一项重要技术&#xff0c;它提供了自动内存管理的机制&#xff0c;极大地简化了开发人员对内存分配和释放的繁琐工作。通过垃圾回收器&#xff0c;我们能够更高效地利用计算机的内存资…