目录
基本介绍
利用Android Studio制作的简易多页面音乐播放器。
包括三个界面,分别为登录界面、选择音乐界面以及播放音乐界面。
登录界面
UI
包含的组件有标题文本,账号密码的可输入文本框,登录按钮。
其中标题文本框与登录按钮很基础,账号密码使用了布局管理器,由水平和垂直的线性布局组成,然后再在线性布局中填入文本框等组件。
以下是登录界面代码
<?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"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="604dp"
android:text="欢迎使用音乐播放器"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="账号:"
android:textSize="24sp" />
<EditText
android:id="@+id/editText_account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:hint="请输入你的账号"
android:inputType="number"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="密码:"
android:textSize="24sp" />
<EditText
android:id="@+id/editText_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:hint="请输入你的密码"
android:inputType="textPassword"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/button_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/buttoncolor"
android:text="登录"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2"
app:layout_constraintVertical_bias="0.494" />
</androidx.constraintlayout.widget.ConstraintLayout>
功能
在常规的给需要添加功能的组件进行好findviewbyid定位后
Button loginButton=findViewById(R.id.button_login);
EditText accountText=findViewById(R.id.editText_account);
EditText passwordText=findViewById(R.id.editText_password);
开始绑定监听器
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String account=accountText.getText().toString();
String password=passwordText.getText().toString();
if(rightAccount(account,password)==true)
{
Toast.makeText(MainActivity.this,"登陆成功",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(MainActivity.this, playview.class);//跳转页面
startActivity(intent);
}
if(!rightAccount(account,password))
{
Toast.makeText(MainActivity.this,"账号或密码错误",Toast.LENGTH_SHORT).show();
//showNumber(v,password);
}
}
});
利用后续的rightAccount方法判断账号密码是否正确,然后给出对应的弹窗提示。
当账号密码输入正确后,通过创建的intent对象进行页面跳转,跳转到第二个音乐选择界面。
Intent 是 Android 中一个非常重要的类,主要用于在应用组件之间(如活动、服务、广播接收器等)进行通信。
Intent 可以用来启动一个新的活动。可以在当前活动中创建一个 Intent 对象,并通过 startActivity 方法启动新的活动;可以用来启动一个服务。可以在需要启动服务的地方创建一个 Intent 对象,并通过 startService 方法启动服务;可以用来发送广播。可以在需要发送广播的地方创建一个 Intent 对象,并通过 sendBroadcast 方法发送广播;可以携带数据,从一个组件传递到另一个组件。可以使用 putExtra 方法在 Intent 对象中添加数据,使用 getExtras 方法获取数据等等。不多赘述,未来一定还会用到。
以下是判断账号密码是否正确的rightAccount方法
public boolean rightAccount(String a,String b)
{
if(a.equals("123")&&b.equals("123"))
{
return true;
}
else
{
return false;
}
}
仅供练习使用,所以账号密码固定为123。
希望以后能够掌握数据库的连接然后添加更多的账户。
登录界面代码
package com.example.musicplayer;
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.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button loginButton=findViewById(R.id.button_login);
EditText accountText=findViewById(R.id.editText_account);
EditText passwordText=findViewById(R.id.editText_password);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String account=accountText.getText().toString();
String password=passwordText.getText().toString();
if(rightAccount(account,password)==true)
{
Toast.makeText(MainActivity.this,"登陆成功",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(MainActivity.this, playview.class);//跳转页面
startActivity(intent);
}
if(!rightAccount(account,password))
{
Toast.makeText(MainActivity.this,"账号或密码错误",Toast.LENGTH_SHORT).show();
//showNumber(v,password);
}
}
});
}
public boolean rightAccount(String a,String b)
{
if(a.equals("123")&&b.equals("123"))
{
return true;
}
else
{
return false;
}
}
}
选择音乐界面
UI
与第一个界面类似,同样使用基础的组件,同样添加了多个叠加的线性布局。工作量有限,只添加了三首音乐作参考。
选择音乐界面源代码
<?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"
tools:context=".playview">
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择音乐"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.065" />
<ScrollView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/num1_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Viva la Vida"
android:textAlignment="center"
android:textSize="24sp" />
<Button
android:id="@+id/button_num1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/buttoncolor"
android:text="播放"
android:textAlignment="textStart"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/num2_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Perfect"
android:textAlignment="center"
android:textSize="24sp" />
<Button
android:id="@+id/button_num2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/buttoncolor"
android:text="播放"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/num3_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="最伟大的作品"
android:textAlignment="center"
android:textSize="24sp" />
<Button
android:id="@+id/button_num3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/buttoncolor"
android:text="播放"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<Button
android:id="@+id/button_return"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/buttoncolor"
android:text="退出登录"
app:iconPadding="1dp"
app:iconSize="30dp"
app:iconTint="@color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
功能
首先是基础的对要使用的组件进行findViewById,然后给左上角的退出登录按钮绑定页面跳转和弹窗功能,跳转到登录界面。
TextView textView1=findViewById(R.id.num1_text);
TextView textView2=findViewById(R.id.num2_text);
TextView textView3=findViewById(R.id.num3_text);
Button returnbutton=findViewById(R.id.button_return);
returnbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(playview.this,MainActivity.class);
startActivity(intent);
Toast.makeText(playview.this,"已退出登录",Toast.LENGTH_SHORT).show();
}
});
为了之后的音乐播放页面的统一性和简洁性,所以需要将音乐选择页面中的部分信息传入到第三页面即音乐播放页面中。
我选择把当前页面的音乐名称传递到后面。
首先定义一个字符串类型的静态变量用于保存音乐名称
private static String music_name; // 静态变量用于保存文本信息
然后在点击每一个播放按钮后进行正常的页面跳转之前先把按钮前的文本框中的信息以字符串类型储存起来
Button button_num1=findViewById(R.id.button_num1);
button_num1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取 TextView 中的文本
music_name=textView1.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
}
);
Button button_num2=findViewById(R.id.button_num2);
button_num2.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
// 获取 TextView 中的文本
music_name=textView2.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
});
Button button_num3=findViewById(R.id.button_num3);
button_num3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
music_name=textView3.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
});
最后定义获取音乐名称的静态方法getTextViewText(),这样后续页面可以直接调用该方法以获取音乐名称
// 静态方法用于其他类获取文本信息
public static String getTextViewText()
{
return music_name;
}
选择音乐界面整体代码
package com.example.musicplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.w3c.dom.Text;
public class playview extends AppCompatActivity {
private static String music_name; // 静态变量用于保存文本信息
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playview);
TextView textView1=findViewById(R.id.num1_text);
TextView textView2=findViewById(R.id.num2_text);
TextView textView3=findViewById(R.id.num3_text);
Button returnbutton=findViewById(R.id.button_return);
returnbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(playview.this,MainActivity.class);
startActivity(intent);
Toast.makeText(playview.this,"已退出登录",Toast.LENGTH_SHORT).show();
}
});
Button button_num1=findViewById(R.id.button_num1);
button_num1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取 TextView 中的文本
music_name=textView1.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
}
);
Button button_num2=findViewById(R.id.button_num2);
button_num2.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
// 获取 TextView 中的文本
music_name=textView2.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
});
Button button_num3=findViewById(R.id.button_num3);
button_num3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
music_name=textView3.getText().toString();
Intent intent = new Intent(playview.this, music1.class);
startActivity(intent);
}
});
}
// 静态方法用于其他类获取文本信息
public static String getTextViewText()
{
return music_name;
}
}
播放音乐界面
UI
这个页面前端放置了Seekbar和ImageView两个组件,前者用作播放音频的进度条,后者可以针对不同音乐展示不同的图片
其中Seekbar组件需要注意它的UI设置
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:thumb="@drawable/seekbar_thumb"
android:progressTint="@color/colorAccent"
android:progressBackgroundTint="@color/colorPrimary"
android:layout_marginBottom="16dp"
android:max="100"
android:progress="0" />
android:thumb 属性用于定义拖动手柄的样式。在这里,它被设置为 @drawable/seekbar_thumb,表示使用了一个自定义的拖动手柄图像。
android:progressTint 和 android:progressBackgroundTint 属性用于定义进度条的前景(进度)和背景(未完成进度)的颜色。在这里,它们被分别设置为 @color/colorAccent 和 @color/colorPrimary。
android:max 属性定义了进度条的最大值,这里设置为 100。
android:progress 属性定义了进度条的初始值,这里设置为 0,表示初始状态下进度条的进度为 0。
最后是音乐名称文本框以及音乐播放器常规的开始暂停切歌等功能按钮。
以下是播放音乐界面源代码
<?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"
tools:context=".music1">
<TextView
android:id="@+id/music_name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="music name"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="409dp"
android:layout_height="199dp"
android:layout_marginTop="1dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progress_bar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:backgroundTint="@color/buttoncolor"
android:text="播放"
android:textStyle="bold" />
<Button
android:id="@+id/button_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:backgroundTint="@color/buttoncolor"
android:text="暂停播放"
android:textStyle="bold" />
<Button
android:id="@+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:backgroundTint="@color/buttoncolor"
android:text="停止播放"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/button_prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:backgroundTint="@color/buttoncolor"
android:text="上一首"
android:textStyle="bold" />
<Button
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:backgroundTint="@color/buttoncolor"
android:text="下一首"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<SeekBar
android:id="@+id/progress_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:max="100"
android:thumb="@android:drawable/ic_notification_overlay"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.157"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/music_name_text"
app:layout_constraintVertical_bias="0.337" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/music_name_text"
app:srcCompat="@drawable/ic_launcher_foreground" />
</androidx.constraintlayout.widget.ConstraintLayout>
功能
1.获取到上一个页面传过来的音乐名称的信息
分别定义一个全局变量和一个TextView类
private String receivedText;
TextView text;
receivedText通过函数被赋予了音乐名字,然后再代用TextView中的setText方法对于文本框中的文字进行设置
receivedText=playview.getTextViewText();
//将文本设置为传过来的音乐名
text.setText(receivedText);
2.添加图片
需要提前把图片存入到项目中res/drawable文件夹中,尽量不要放在res/raw,这样不方便读取。
我把图片分别命名为pic1,pic2,pic3以方便校对。
接下来把接收到的音乐名字与已知名字进行比对,目的是匹配到正确的图片
ImageView imageView=findViewById(R.id.imageView2);
int imageID;
if(receivedText.equals("Viva la Vida"))
{
imageID= R.drawable.pic1;
}
else if(receivedText.equals("Perfect"))
{
imageID=R.drawable.pic2;
}
else if(receivedText.equals("最伟大的作品"))
{
imageID=R.drawable.pic3;
}
else
{
imageID=R.drawable.ic_launcher_foreground;
}
imageView.setImageResource(imageID);
其中,setImageResource 方法是 Android 中 ImageView 类的一个方法,用于设置 ImageView 显示的图片资源。该方法接受一个资源 ID 作为参数,资源 ID 通常是一个 R.drawable 类型的值。
id是int类型的常量。
3.进度条
使用seekbar组件作为进度条,seekbar有自己的监听器,由之前的onclicklistener不同
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
这个监听器中包含了三个行为监听器,分别在拖动时调用、开始拖动时调用、停止拖动时调用。因为需要实时监控音乐播放进度,所以只在第一个行为后有操作。
if 判断语句中第一个判断条件mediaPlayer现在可以视作当前是否正在播放,后续会展开说明,波尔类型的fromUser则是判断是否为用户自己手动操作,而不是进度条自动追踪跳转的结果。其他调用的方法在注释中均有解释。
具体函数如下
seekBar=findViewById(R.id.progress_bar);//拖动进度条
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
//当用户拖动进度条时调用
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer!=null&&fromUser==true)//fromUser指的是必须是用户手动调整进度条才执行
{
//seekTo() 是 MediaPlayer 类的一个方法,用于将播放位置移动到指定的时间点。
// 它接受一个参数,表示要移动到的时间点(以毫秒为单位)。调用 seekTo() 方法后,MediaPlayer 将会从指定的时间点开始播放音频或视频。
//progress 是用户拖动 SeekBar 时当前的进度值,范围是 0 到 SeekBar 的最大值。
//mediaPlayer.getDuration() 返回音频或视频文件的总时长,以毫秒为单位。
mediaPlayer.seekTo(progress*mediaPlayer.getDuration()/100);
}
if(mediaPlayer==null&&fromUser==true)
{
play();
mediaPlayer.seekTo(progress*mediaPlayer.getDuration()/100);
}
}
@Override
//当用户开始拖动进度条时调用
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
//当用户停止拖动进度条时调用
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
设定完手动调整进度条的操作之后,需要添加进度条的自动实时追踪功能。
Timer方法可以完成定时执行某一任务的操作
//创建一个定时器,让进度条实时运动
Timer timer=new Timer();//创建Timer对象
//scheduleAtFixedRate方法会按照固定的速率执行指定的任务
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if(mediaPlayer!=null&&isPlaying==true)
{
//获取当前音频的播放位置
int currentPosition=mediaPlayer.getCurrentPosition();
//获取音频的总时长
int totalDuration=mediaPlayer.getDuration();
//计算当前播放位置的百分比
int progress=(int)(currentPosition*100/totalDuration);
//更新进度条的进度
seekBar.setProgress(progress);
}
}
},0,1000);
4.MediaPlayer
MediaPlayer 是 Android 提供的一个类,用于播放音频和视频文件。它是一个功能强大且灵活的媒体播放工具,支持从本地文件、应用资源和网络流媒体中播放音频和视频。MediaPlayer 提供了丰富的控制功能,如播放、暂停、停止、快进、快退等。
其中OnCompletionListener监听器就包含于MediaPlayer,用于监控音频播放是否结束
关于播放的控制:
开始播放
mediaPlayer.start();
暂停播放
mediaPlayer.pause();
停止播放
mediaPlayer.stop();
mediaPlayer.prepare(); // 如果需要再次播放,必须调用 prepare 或 prepareAsync
快进到指定位置
mediaPlayer.seekTo(milliseconds);
设置循环播放
mediaPlayer.setLooping(true);
关于资源管理和释放:
释放资源
mediaPlayer.release();
mediaPlayer = null;
释放资源
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
回到项目中
定义MediaPlayer类,执行该页面中所有播放器的操作
private MediaPlayer mediaPlayer;
5.播放、暂停、停止
提前定义一个波尔值,标记是否正在播放,在播放、暂停、停止状态变化时需要及时修改,这对后续切换歌曲有很大的影响。
private boolean isPlaying=false;//定义一个变量记录是否正在播放音乐
给播放、暂停、停止按钮添加点击监听器,在后面完善需要调用的函数
play_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
play();
}
});
pause_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pause();
}
});
stop_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stop();
}
});
播放:
提前把需要准备播放的音乐存入到res/raw文件中,并且音乐名称中只能包含数字字母和下划线。
通过之前从上个页面接收到的receivedText判断当前需要播放哪首歌,将它与音频一一对应。
用setOnCompletionListener方法监控音乐是否播放完毕。
private void play() {//播放方法
//首先检查 mediaPlayer 是否为 null。如果是 null,说明播放器还没有被初始化。
if(mediaPlayer==null)
{
if(receivedText.equals("Viva la Vida")) {
// 使用 MediaPlayer.create() 方法创建一个新的 MediaPlayer 实例
mediaPlayer = MediaPlayer.create(music1.this, R.raw.viva_la_vida);
}
else if(receivedText.equals("Perfect"))
{
mediaPlayer = MediaPlayer.create(music1.this, R.raw.perfect);
}
else
{
mediaPlayer = MediaPlayer.create(music1.this, R.raw.zwddzp);
}
//设置一个监听器 setOnCompletionListener,当音频播放完成时,会调用 stop() 方法。
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stop();
}
});
}
mediaPlayer.start();
isPlaying=true;
}
停止与暂停:
可以直接调用MediaPlayer中已经默认设定好的暂停和停止方法进行操作。但是要注意停止播放后要释放资源,还原进度条。
private void pause() {
if(mediaPlayer!=null&&mediaPlayer.isPlaying())
{
mediaPlayer.pause();
isPlaying=false;
}
}
private void stop() {
//检查 mediaPlayer 是否不为 null。如果是,调用 release() 方法释放 MediaPlayer 相关的资源
if(mediaPlayer!=null)
{
seekBar.setProgress(0);//进度条回到起点
mediaPlayer.release();
//将 mediaPlayer 变量设为 null,确保下次调用 playMusic() 时会重新创建一个新的 MediaPlayer 实例。
mediaPlayer=null;
isPlaying=false;
}
}
6.切换音乐
需要按顺序切换音乐,可以把音乐放到数组中实现切换和循环。
private int currentTrack;//记录当前是第几首歌
private int[] tracks={R.raw.viva_la_vida,R.raw.perfect,R.raw.zwddzp};//把音乐的id放入数组中
通过释放原来音乐的MediaPlayer对象,创建新音乐的MeidaPlayer对象完成。特别注意边界条件的判定,比如最后一首歌点击下一首需要跳转到第一首,第一首歌点击上一首需要跳转到最后一首。另外,通过当前音乐的播放状态保证切换后保持相同的状态,比如原来音乐正在播放时切换,则下一首歌应该从头自动播放。
上一首:
private void prev()
{
seekBar.setProgress(0);//进度条回到起点
if(mediaPlayer!=null)
{
if(currentTrack>0)
{
currentTrack--;
}
else if(currentTrack<=0)
{
currentTrack = tracks.length-1;
}
mediaPlayer.release();
mediaPlayer=MediaPlayer.create(this,tracks[currentTrack]);
if(isPlaying==true)
{
play();
}
}
if(mediaPlayer==null)
{
if(currentTrack>0)
{
currentTrack--;
}
else if(currentTrack<=0)
{
currentTrack = tracks.length-1;
}
mediaPlayer=MediaPlayer.create(this,tracks[currentTrack]);
}
change_ui();
text.setText(receivedText);
}
下一首:
private void next()
{
seekBar.setProgress(0);//进度条回到起点
if(mediaPlayer!=null)
{
if (currentTrack < tracks.length-1)//不是末位
{
currentTrack++;
}
else if (currentTrack == tracks.length-1)
{
currentTrack = 0;
}
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(this, tracks[currentTrack]);
if(isPlaying==true)
{
play();
}
}
if(mediaPlayer==null)//还没播放
{
if (currentTrack < tracks.length-1)//不是末位
{
currentTrack++;
}
else if (currentTrack == tracks.length-1)
{
currentTrack = 0;
}
mediaPlayer = MediaPlayer.create(this, tracks[currentTrack]);
}
change_ui();
text.setText(receivedText);
}
7.切换图片与名称
把次序与图片以及名称进行绑定
private void change_ui()
{
if(currentTrack==0)
{
receivedText="Viva la Vida";
}
else if(currentTrack==1)
{
receivedText="Perfect";
}
else if(currentTrack==2)
{
receivedText="最伟大的作品";
}
ImageView imageView = findViewById(R.id.imageView2);
int imageID;
if (currentTrack == 0) {
imageID = R.drawable.pic1;
} else if (currentTrack == 1) {
imageID = R.drawable.pic2;
} else {
imageID = R.drawable.pic3;
}
imageView.setImageResource(imageID);
}
8.释放内存OnPause,OnDestory
为了保证在切换页面后音乐停止,需要添加自动释放内存的方法,以免造成多首音乐同时播放的情况。
Android 提供了一套完整的生命周期方法,如 onCreate(), onStart(), onResume(), onPause(), onStop(), 和 onDestroy(),以管理 Activity 的状态和资源,通过这些方法,你可以捕捉到界面切换行为,并做出相应的处理。
onPause 方法在 Activity 不再处于前台但仍然可见时调用。常见的情况包括:
·启动另一个 Activity。
·打开对话框。
·切换到另一个应用程序。
在 onPause 中,你应该释放不再需要的资源(如暂停动画、停止音乐等),以便在用户返回该 Activity 时能迅速恢复。
· 具体触发情况
·当一个新的 Activity 被启动,而当前 Activity 即将被覆盖(但仍然可见,比如部分透明的 Activity 覆盖在上面)。
·当用户按下 Home 键,当前 Activity 被放到后台。
·当前 Activity 打开一个对话框。
onDestroy 方法在 Activity 被销毁之前调用。常见的情况包括:
·用户完全退出 Activity。
·Activity 因内存限制被系统销毁。
·开发者在代码中调用 finish()。
在 onDestroy 中,你应该释放所有剩余的资源,进行清理工作。
具体触发情况
·用户按下 Back 键退出 Activity。
·Activity 通过代码调用 finish() 方法结束。
·系统为了回收内存而销毁 Activity。
具体代码如下
protected void onPause()//可以监控到页面的跳转,切换页面后可以自动释放资源
{
super.onPause();
stop();
}
protected void onDestroy()
{
super.onDestroy();
stop();
}
最后是播放音乐界面的完整代码
package com.example.musicplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class music1 extends AppCompatActivity {
private MediaPlayer mediaPlayer;
private int currentTrack;//记录当前是第几首歌
private int[] tracks={R.raw.viva_la_vida,R.raw.perfect,R.raw.zwddzp};//把音乐的id放入数组中
private boolean isPlaying=false;//定义一个变量记录是否正在播放音乐
private String receivedText;
SeekBar seekBar;
TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music1);
//找到音乐名称文本框
text=findViewById(R.id.music_name_text);
//调取playview中的函数
receivedText=playview.getTextViewText();
//将文本设置为传过来的音乐名
text.setText(receivedText);
Button play_button=findViewById(R.id.button_play);
Button pause_button=findViewById(R.id.button_pause);
Button stop_button=findViewById(R.id.stop_button);
Button prev_button=findViewById(R.id.button_prev);
Button next_button=findViewById(R.id.button_next);
//图片
//将图片放在 res/raw 文件夹中,虽然可以读取图片,但是不能直接用 setImageResource 来显示。
// setImageResource 方法需要一个 drawable 资源 ID,而不是 raw 资源 ID。
ImageView imageView=findViewById(R.id.imageView2);
int imageID;
if(receivedText.equals("Viva la Vida"))
{
imageID= R.drawable.pic1;
}
else if(receivedText.equals("Perfect"))
{
imageID=R.drawable.pic2;
}
else if(receivedText.equals("最伟大的作品"))
{
imageID=R.drawable.pic3;
}
else
{
imageID=R.drawable.ic_launcher_foreground;
}
imageView.setImageResource(imageID);
//进度条
seekBar=findViewById(R.id.progress_bar);//拖动进度条
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
//当用户拖动进度条时调用
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer!=null&&fromUser==true)//fromUser指的是必须是用户手动调整进度条才执行
{
//seekTo() 是 MediaPlayer 类的一个方法,用于将播放位置移动到指定的时间点。
// 它接受一个参数,表示要移动到的时间点(以毫秒为单位)。调用 seekTo() 方法后,MediaPlayer 将会从指定的时间点开始播放音频或视频。
//progress 是用户拖动 SeekBar 时当前的进度值,范围是 0 到 SeekBar 的最大值。
//mediaPlayer.getDuration() 返回音频或视频文件的总时长,以毫秒为单位。
mediaPlayer.seekTo(progress*mediaPlayer.getDuration()/100);
}
if(mediaPlayer==null&&fromUser==true)
{
play();
mediaPlayer.seekTo(progress*mediaPlayer.getDuration()/100);
}
}
@Override
//当用户开始拖动进度条时调用
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
//当用户停止拖动进度条时调用
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//创建一个定时器,让进度条实时运动
Timer timer=new Timer();//创建Timer对象
//scheduleAtFixedRate方法会按照固定的速率执行指定的任务
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if(mediaPlayer!=null&&isPlaying==true)
{
//获取当前音频的播放位置
int currentPosition=mediaPlayer.getCurrentPosition();
//获取音频的总时长
int totalDuration=mediaPlayer.getDuration();
//计算当前播放位置的百分比
int progress=(int)(currentPosition*100/totalDuration);
//更新进度条的进度
seekBar.setProgress(progress);
}
}
},0,1000);
//播放,暂停,停止
play_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
play();
}
});
pause_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pause();
}
});
stop_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stop();
}
});
//下一首,上一首按钮
next_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
next();
}
});
prev_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
prev();
}
});
}
private void play() {//播放方法
//首先检查 mediaPlayer 是否为 null。如果是 null,说明播放器还没有被初始化。
if(mediaPlayer==null)
{
if(receivedText.equals("Viva la Vida")) {
// 使用 MediaPlayer.create() 方法创建一个新的 MediaPlayer 实例
mediaPlayer = MediaPlayer.create(music1.this, R.raw.viva_la_vida);
}
else if(receivedText.equals("Perfect"))
{
mediaPlayer = MediaPlayer.create(music1.this, R.raw.perfect);
}
else
{
mediaPlayer = MediaPlayer.create(music1.this, R.raw.zwddzp);
}
//设置一个监听器 setOnCompletionListener,当音频播放完成时,会调用 stop() 方法。
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stop();
}
});
}
mediaPlayer.start();
isPlaying=true;
}
private void pause() {
if(mediaPlayer!=null&&mediaPlayer.isPlaying())
{
mediaPlayer.pause();
isPlaying=false;
}
}
private void stop() {
//检查 mediaPlayer 是否不为 null。如果是,调用 release() 方法释放 MediaPlayer 相关的资源
if(mediaPlayer!=null)
{
seekBar.setProgress(0);//进度条回到起点
mediaPlayer.release();
//将 mediaPlayer 变量设为 null,确保下次调用 playMusic() 时会重新创建一个新的 MediaPlayer 实例。
mediaPlayer=null;
isPlaying=false;
}
}
private void next()
{
seekBar.setProgress(0);//进度条回到起点
if(mediaPlayer!=null)
{
if (currentTrack < tracks.length-1)//不是末位
{
currentTrack++;
}
else if (currentTrack == tracks.length-1)
{
currentTrack = 0;
}
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(this, tracks[currentTrack]);
if(isPlaying==true)
{
play();
}
}
if(mediaPlayer==null)//还没播放
{
if (currentTrack < tracks.length-1)//不是末位
{
currentTrack++;
}
else if (currentTrack == tracks.length-1)
{
currentTrack = 0;
}
mediaPlayer = MediaPlayer.create(this, tracks[currentTrack]);
}
change_ui();
text.setText(receivedText);
}
private void prev()
{
seekBar.setProgress(0);//进度条回到起点
if(mediaPlayer!=null)
{
if(currentTrack>0)
{
currentTrack--;
}
else if(currentTrack<=0)
{
currentTrack = tracks.length-1;
}
mediaPlayer.release();
mediaPlayer=MediaPlayer.create(this,tracks[currentTrack]);
if(isPlaying==true)
{
play();
}
}
if(mediaPlayer==null)
{
if(currentTrack>0)
{
currentTrack--;
}
else if(currentTrack<=0)
{
currentTrack = tracks.length-1;
}
mediaPlayer=MediaPlayer.create(this,tracks[currentTrack]);
}
change_ui();
text.setText(receivedText);
}
private void change_ui()
{
if(currentTrack==0)
{
receivedText="Viva la Vida";
}
else if(currentTrack==1)
{
receivedText="Perfect";
}
else if(currentTrack==2)
{
receivedText="最伟大的作品";
}
ImageView imageView = findViewById(R.id.imageView2);
int imageID;
if (currentTrack == 0) {
imageID = R.drawable.pic1;
} else if (currentTrack == 1) {
imageID = R.drawable.pic2;
} else {
imageID = R.drawable.pic3;
}
imageView.setImageResource(imageID);
}
protected void onPause()//可以监控到页面的跳转,切换页面后可以自动释放资源
{
super.onPause();
stop();
}
protected void onDestroy()
{
super.onDestroy();
stop();
}
}
END
安卓开发自学笔记