目录
1.SoundPool介绍
MediaPlayer虽然也能播放音频,但是它有资源占用量较高、延迟时间较长、不支持多个音频同时播放等缺点。这些缺点决定了MediaPlayer在某些场合的使用情况不会很理想,例如在对时间精准度要求相对较高的场景。而SoundPool一般用来播放密集、急促而又短暂的音效,比如: "滴滴一下,马上出发”。
2.使用SoundPool播放音频
实现代码
SoundActivity.java
package com.example.mediademo; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.media.SoundPool; import android.os.Bundle; import android.view.View; import java.util.ArrayList; import java.util.List; public class SoundActivity extends AppCompatActivity implements MyAdapter.OnItemClickListener { static class Sound{ String name; int soundId; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSoundId() { return soundId; } public void setSoundId(int soundId) { this.soundId = soundId; } public Sound(String name, int soundId) { this.name = name; this.soundId = soundId; } } List<Sound> data; SoundPool soundPool; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sound); RecyclerView recyclerView = findViewById(R.id.recyclerView); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(linearLayoutManager); soundPool = new SoundPool.Builder().setMaxStreams(6).build(); data = new ArrayList<>(); data.add(new Sound("a4",soundPool.load(this,R.raw.a4,1))); data.add(new Sound("a5",soundPool.load(this,R.raw.a5,1))); data.add(new Sound("a6",soundPool.load(this,R.raw.a6,1))); data.add(new Sound("a7",soundPool.load(this,R.raw.a7,1))); data.add(new Sound("a8",soundPool.load(this,R.raw.a8,1))); data.add(new Sound("a9",soundPool.load(this,R.raw.a9,1))); MyAdapter myAdapter = new MyAdapter(data, recyclerView, this); myAdapter.setOnItemClickListener(this); recyclerView.setAdapter(myAdapter); } @Override public void onItemClick(int childAdapterPosition) { Sound sound = data.get(childAdapterPosition); soundPool.play(sound.getSoundId(),1.0f,1.0f, 1,0,1.0f); } @Override protected void onDestroy() { super.onDestroy(); for (Sound sound : data) { soundPool.unload(sound.getSoundId()); } soundPool.release(); } }
布局文件 activity_sound.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" tools:context=".SoundActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
使用了recyclerview进行布局 因此有MyAdapter.java
package com.example.mediademo; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.time.temporal.Temporal; import java.util.List; public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements View.OnClickListener { private final List<SoundActivity.Sound> data; private final Context context; private final RecyclerView recyclerView; private OnItemClickListener listener; public MyAdapter(List<SoundActivity.Sound> data, RecyclerView recyclerView, Context context){ this.data = data; this.recyclerView = recyclerView; this.context = context; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { TextView textView = new TextView(context); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.topMargin = 18; layoutParams.leftMargin = 18; textView.setLayoutParams(layoutParams); textView.setOnClickListener(this); return new MyViewHolder(textView); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { ((TextView)holder.itemView).setText(data.get(position).getName()); } @Override public int getItemCount() { return data.size(); } @Override public void onClick(View v) { if (listener != null){ listener.onItemClick(recyclerView.getChildAdapterPosition(v)); } } public void setOnItemClickListener(OnItemClickListener listener){ this.listener = listener; } interface OnItemClickListener { void onItemClick(int childAdapterPosition); } public class MyViewHolder extends RecyclerView.ViewHolder { public MyViewHolder(@NonNull View itemView) { super(itemView); } } }
实现效果
点击对应文字即可播放对应音效
3 .总结
初始化
SoundPool.Builder spb = new SoundPool.Builder(); spb.setMaxStreams(10); spb.setAudioAttributes(null); //转换音频格式 SoundPool sp = spb.build(); //创建SoundPool对象
常用方法介绍:
①加载声音资源:
load(Context context, int resId, int priority)
load(String path, int priority)
load(FileDescriptor fd, long offset, long length, int priority)
load(AssetFileDescriptor afd, int priority) 上述方法都会返回一个声音的ID,后面我们可以通过这个ID来播放指定的声音
参数介绍:
-
context:上下文
-
resId:资源id
-
priority:没什么用的一个参数,建议设置为1,保持和未来的兼容性
-
path:文件路径
-
FileDescriptor:貌似是流吧,这个我也不知道
-
AssetFileDescriptor:从asset目录读取某个资源文件,用法: AssetFileDescriptor descriptor = assetManager.openFd("biaobiao.mp3");
②播放控制:
play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
参数依次是:
-
soundID:Load()返回的声音ID号
-
leftVolume:左声道音量设置
-
rightVolume:右声道音量设置
-
priority:指定播放声音的优先级,数值越高,优先级越大。
-
loop:指定是否循环:-1表示无限循环,0表示不循环,其他值表示要重复播放的次数
-
rate:指定播放速率:1.0的播放率可以使声音按照其原始频率,而2.0的播放速率,可以使声音按照其 原始频率的两倍播放。如果为0.5的播放率,则播放速率是原始频率的一半。播放速率的取值范围是0.5至2.0。
③资源释放:
可以调用release()方法释放所有SoundPool对象占据的内存和资源,当然也可以根据声音 ID来释放!
本文使用初始化方法
soundPool = new SoundPool.Builder().setMaxStreams(6).build();
本文加载音频
soundPool.load(this,R.raw.a4,1)
本文播放音效
soundPool.play(sound.getSoundId(),1.0f,1.0f, 1,0,1.0f);
本文结束
soundPool.unload(sound.getSoundId()); soundPool.release();