複数のプレーヤー インスタンスをサポートする、Android にパッケージ化されたエレガントな MediaPlayer オーディオ プレーヤーの例:
public class AudioPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener {
private static AudioPlayer instance;
private List<AudioPlayerListener> listeners = new ArrayList<>();
private MediaPlayer mediaPlayer;
private Context context;
private AudioPlayer(Context context) {
this.context = context;
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void addListener(AudioPlayerListener listener) {
listeners.add(listener);
}
public void removeListener(AudioPlayerListener listener) {
listeners.remove(listener);
}
public void play(String url) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
public void release() {
mediaPlayer.release();
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStart();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStop();
}
}
public interface AudioPlayerListener {
void onAudioPlayerStart();
void onAudioPlayerStop();
}
}
上記のコードでは、getInstance()
メソッド を使用して のAudioPlayer
シングルトン オブジェクトが取得され、パラメータがContext
オブジェクトに渡されます。
getInstance()
メソッド内ではシングルトンオブジェクトが空かどうかを判断し、空の場合は新規オブジェクトを作成しAudioPlayer
、そうでない場合は既存のシングルトンオブジェクトを返します。
これにより、同じプロセス内にAudioPlayer
インスタンスが1 つだけ存在することが保証され、複数のオーディオ ファイルの再生を管理するのに便利です。
このクラスには、AudioPlayerListener
プレーヤーのステータスを監視するためのインターフェイスがあります。プレーヤーのメソッドonPrepared()
とonCompletion()
メソッドでコールバックをトリガーして、すべてのリスナーに通知します。
リスナーは、addListener()
およびメソッドを呼び出すことで追加または削除できます。removeListener()
メソッドを呼び出してplay()
オーディオを再生し、オーディオの URL を渡し、stop()
メソッドを呼び出して再生を停止し、release()
メソッドを呼び出してプレーヤーのリソースを解放します。
以下の手順に従ってシングルトン クラスを呼び出すことができますAudioPlayer
。
- を使用する必要がある場合は
AudioPlayer
、まずContext
次のようにオブジェクトを取得しますMainActivity
。
public class MainActivity extends AppCompatActivity {
private AudioPlayer audioPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioPlayer = AudioPlayer.getInstance(this);
}
//...
}
2.AudioPlayerListener
オーディオ再生の開始イベントと終了イベントを監視するインターフェイスの実装を追加します。
public class MainActivity extends AppCompatActivity implements AudioPlayer.AudioPlayerListener {
// ...
@Override
public void onAudioPlayerStart() {
// 音频播放开始
}
@Override
public void onAudioPlayerStop() {
// 音频播放结束
}
}
3. オーディオを再生する必要がある場合は、次AudioPlayer
のメソッドを呼び出しますplay()
。
audioPlayer.play(url);
その中には、url
音声ファイルの URL アドレスがあります。
4. オーディオ再生を停止する必要がある場合は、次AudioPlayer
のメソッドを呼び出しますstop()
。
audioPlayer.stop();
MediaPlayer
インスタンスを解放する必要がある場合は、次AudioPlayer
のメソッドを呼び出すことができますrelease()
。
audioPlayer.release();
5.addListener()
およびremoveListener()
メソッドを使用して、実装を追加および削除しAudioPlayerListener
、オーディオ再生イベントを監視します。
audioPlayer.addListener(this);
audioPlayer.removeListener(this);
このようにして、シングルトン モードAudioPlayer
クラスを使用してオーディオを再生できます。シングルトン インスタンスは 1 つだけであるため、release()
他の場所でのオーディオ再生に影響を与えないようにメソッドを呼び出すときは注意してください。
他の場所でのオーディオ再生への影響を避けるために、AudioPlayer
クラス内のオーディオ フォーカスを制御するメソッドをいくつか追加できます。
ここのクラスを使用する必要があります。このクラスAudioManager
は、オーディオ システム サービスにアクセスするメソッドを提供し、アプリケーションのオーディオ セッションとオーディオ ルーティングを制御できます。
具体的な実装は以下の通りです。
public class AudioPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener {
private static AudioPlayer instance;
private List<AudioPlayerListener> listeners = new ArrayList<>();
private MediaPlayer mediaPlayer;
private Context context;
private AudioManager audioManager;
private boolean audioFocusGranted = false;
private AudioPlayer(Context context) {
this.context = context;
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void addListener(AudioPlayerListener listener) {
listeners.add(listener);
}
public void removeListener(AudioPlayerListener listener) {
listeners.remove(listener);
}
public void play(String url) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
requestAudioFocus();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
abandonAudioFocus();
}
public void release() {
stop();
mediaPlayer.release();
}
private void requestAudioFocus() {
if (!audioFocusGranted) {
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
audioFocusGranted = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
}
private void abandonAudioFocus() {
if (audioFocusGranted) {
audioManager.abandonAudioFocus(this);
audioFocusGranted = false;
}
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStart();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStop();
}
abandonAudioFocus();
}
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
mediaPlayer.start();
break;
case AudioManager.AUDIOFOCUS_LOSS:
stop();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
mediaPlayer.pause();
break;
}
}
public interface AudioPlayerListener {
void onAudioPlayerStart();
void onAudioPlayerStop();
}
}
上記のコードでは次のようになります。
audioManager
オブジェクトは、メソッドを通じてサービスをgetSystemService()
取得することによって初期化されますAUDIO_SERVICE
。play()
オーディオを再生する前にオーディオフォーカスを要求するメソッド。stop()
メソッドは、オーディオ再生を停止した後にオーディオ フォーカスを解放します。requestAudioFocus()
このメソッドは、オーディオ フォーカスを要求するために使用されます。フォーカスが利用可能な場合、オーディオ フォーカス許可フラグはaudioFocusGranted
true に設定されます。abandonAudioFocus()
このメソッドはオーディオ フォーカスを解放するために使用され、フォーカスが解放されると、オーディオ フォーカス許可フラグがaudioFocusGranted
false に設定されます。onAudioFocusChange()
このメソッドはフォーカスが変化するときに呼び出され、フォーカス変化の種類に応じて異なる処理方法が採用されます。- このメソッドでは
onCompletion()
、オーディオの再生が完了したら、オーディオのフォーカスを解放します。
この実装はほとんどの状況を満たしますが、次のようないくつかの問題が依然として発生する可能性があります。
- 複数のオーディオ フォーカス リクエストが同時に発生すると、競合の問題が発生する可能性があります。
- オーディオ フォーカスはデバイスごとに異なる方法で割り当てられる場合があり、追加の適応が必要になる場合があります。
したがって、オーディオのフォーカスを完全に制御する方法は、ケースバイケースで調整し、改良する必要があります。
複数のオーディオ フォーカス リクエストが同時に発生すると、競合の問題が発生し、最終結果が期待どおりにならない場合があります。競争問題を最適化するには、次の 2 つのオプションを検討できます。
-
戦略モード: 戦略モードを通じて、さまざまなオーディオ フォーカス リクエストの処理方法を分離し、さまざまなリクエストを異なる方法で処理できます。このようにして、相互間の競争問題を回避することができます。同時に、戦略モードにより、新しいオーディオ フォーカス戦略を簡単に拡張できます。
-
優先システム: 優先システムにより、音声フォーカス要求ごとに異なる優先順位を設定でき、複数の要求が同時に到着した場合、競合やその他の問題を回避するために、優先順位に従って順番に処理されます。
それまでの間、使用できる追加のトリックがいくつかあります。
-
キュー処理: 複数のオーディオ フォーカス リクエストが同時に到着した場合、それらのリクエストはキュー内で先入れ先出し方式で処理され、競合や競合を避けることができます。
-
コールバック処理: 複数のオーディオ フォーカス リクエストが同時に到着した場合、コールバック処理を使用できます。リクエストが処理されると、次のリクエストを処理して、競合や競合を回避できます。
要約すると、ポリシー モードを使用するか優先システムを使用するか、キュー処理またはコールバック処理を使用するかに関係なく、複数のオーディオ フォーカス リクエストを処理するときは、パフォーマンスと処理の明瞭さを最適化する方法を選択する必要があります。
以下は、優先順位システムを使用して複数のオーディオ フォーカス リクエストを処理する簡単なコード例です。
public class AudioFocusManager {
private final List<AudioFocusRequest> requests = new ArrayList<>(); // 待处理的音频焦点请求列表
public void requestAudioFocus(AudioFocusRequest request) {
requests.add(request); // 将请求加入待处理列表
Collections.sort(requests, new AudioFocusRequestComparator()); // 按照优先级排序
processRequests(); // 处理请求
}
private void processRequests() {
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
for (AudioFocusRequest request : requests) {
int result = audioManager.requestAudioFocus(request.getOnAudioFocusChangeListener(),
request.getStreamType(), request.getDurationHint());
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// 请求被拒绝
break;
} else {
// 请求被接受,处理下一个请求
requests.remove(request);
}
}
}
private static class AudioFocusRequestComparator implements Comparator<AudioFocusRequest> {
@Override
public int compare(AudioFocusRequest r1, AudioFocusRequest r2) {
return r2.getPriority() - r1.getPriority();
}
}
}
上記のコードでは、AudioFocusManager
複数のオーディオ フォーカス リクエストを処理するクラスを定義しました。このメソッドを呼び出すとrequestAudioFocus
、リクエストは保留リストに追加され、優先度に従って並べ替えられ、リクエストは順番に処理されます。リクエストが拒否された場合は処理が停止し、拒否された場合は次のリクエストで処理が続行されます。
ここでの仮定がAudioFocusRequest
満たされていることは注目に値します。具体的な実装方法は、実際のビジネスニーズに応じてカスタマイズできます。たとえば、戦略パターンを使用して、さまざまなオーディオ フォーカス リクエストの処理方法を実装したり、コールバックを使用して UI インターフェイスなどを更新したりできます。
上の例のようなオーディオ フォーカス マネージャーを使用するには、次の手順を実行します。
AudioFocusRequest
次のプロパティとメソッドを持つ必要がある というクラスを作成します。
priority
- 整数で表されるリクエストの優先度durationHint
- リクエストの継続時間 (ミリ秒)streamType
- 要求されたオーディオの種類 (例:STREAM_MUSIC
)onAudioFocusChangeListener
- フォーカスの変更を処理するリスナー。内部クラスを使用して実装することもできます。
-
というクラスを作成し
AudioFocusManager
、そのクラスで、requestAudioFocus
オブジェクトを受け入れAudioFocusRequest
、それをリストに追加し、優先順位付けアルゴリズムを使用して保留中のリクエストを並べ替えるメソッドを作成します。次に、リクエストの処理を実行し、リスト内の他の未処理のリクエストを追跡します。 -
オーディオ フォーカスを管理する必要があるアクティビティで、オブジェクトをインスタンス化し、オーディオ フォーカスを取得する必要があるメソッドを
AudioFocusManager
呼び出して、既にインスタンス化されているオブジェクトを渡します。requestAudioFocus
AudioFocusRequest
こうすることで、アプリケーションはオーディオ フォーカスを効率的に制御し、複数のリクエストを処理できるようになります。
上記の手順を使用してオーディオ フォーカスを管理する方法を示す簡単な例を次に示します。
まず、AudioFocusRequest
という名前の Java クラスを作成します。このクラスには、次のプロパティとメソッドが含まれている必要があります。
public class AudioFocusRequest {
private int priority;
private int durationHint;
private int streamType;
private OnAudioFocusChangeListener onAudioFocusChangeListener;
public AudioFocusRequest(int priority, int durationHint, int streamType, OnAudioFocusChangeListener onAudioFocusChangeListener) {
this.priority = priority;
this.durationHint = durationHint;
this.streamType = streamType;
this.onAudioFocusChangeListener = onAudioFocusChangeListener;
}
public int getPriority() {
return priority;
}
public int getDurationHint() {
return durationHint;
}
public int getStreamType() {
return streamType;
}
public OnAudioFocusChangeListener getOnAudioFocusChangeListener() {
return onAudioFocusChangeListener;
}
}
次に、AudioFocusManager
という名前の Java クラスを作成し、requestAudioFocus
次のコードでメソッドを記述します。
public class AudioFocusManager {
private List<AudioFocusRequest> audioFocusRequests = new ArrayList<>();
public void requestAudioFocus(AudioFocusRequest audioFocusRequest) {
audioFocusRequests.add(audioFocusRequest);
Collections.sort(audioFocusRequests, new Comparator<AudioFocusRequest>() {
@Override
public int compare(AudioFocusRequest r1, AudioFocusRequest r2) {
return r2.getPriority() - r1.getPriority();
}
});
processAudioFocusRequests();
}
private void processAudioFocusRequests() {
for (int i = 0; i < audioFocusRequests.size(); i++) {
AudioFocusRequest audioFocusRequest = audioFocusRequests.get(i);
int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
result = audioManager.requestAudioFocus(audioFocusRequest.getOnAudioFocusChangeListener(),
audioFocusRequest.getStreamType(), audioFocusRequest.getDurationHint());
}
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
audioFocusRequests.remove(audioFocusRequest);
}
}
}
}
最後に、オーディオ フォーカスを管理する必要があるアクティビティのサンプル コードに示されているように、AudioFocusManager
と を使用できますAudioFocusRequest
。次に例を示します。
AudioFocusRequest audioFocusRequest = new AudioFocusRequest(AudioManager.AUDIOFOCUS_GAIN, 1000, AudioManager.STREAM_MUSIC, new OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
// 处理音频焦点变化
}
});
AudioFocusManager audioFocusManager = new AudioFocusManager();
audioFocusManager.requestAudioFocus(audioFocusRequest);
この例では、オブジェクトを作成しAudioFocusRequest
、それを使用してAudioFocusManager
オーディオ フォーカスをリクエストし、リクエストを処理するコールバック メソッドを指定します。
以下は、AudioFocusManager クラスを使用して複数のオーディオ フォーカス リクエストを処理するサンプル コードです。
public class AudioFocusManager implements AudioManager.OnAudioFocusChangeListener {
private AudioManager audioManager;
private Map<AudioFocusRequest, AudioFocusChangeListener> audioFocusRequests;
public AudioFocusManager(Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioFocusRequests = new HashMap<>();
}
public void requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener) {
audioFocusRequests.put(audioFocusRequest, audioFocusChangeListener);
updateAudioFocus();
}
public void abandonAudioFocus(AudioFocusRequest audioFocusRequest) {
audioFocusRequests.remove(audioFocusRequest);
updateAudioFocus();
}
private void updateAudioFocus() {
AudioFocusRequest topAudioFocusRequest = getTopAudioFocusRequest();
if (topAudioFocusRequest == null) {
audioManager.abandonAudioFocus(this);
} else {
int focusRequestResult = audioManager.requestAudioFocus(
topAudioFocusRequest.getAudioFocusRequest(),
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
AudioFocusChangeListener audioFocusChangeListener = audioFocusRequests.get(topAudioFocusRequest);
if (audioFocusChangeListener != null) {
audioFocusChangeListener.onAudioFocusChanged(true);
}
}
}
}
private AudioFocusRequest getTopAudioFocusRequest() {
AudioFocusRequest topAudioFocusRequest = null;
for (AudioFocusRequest audioFocusRequest : audioFocusRequests.keySet()) {
if (topAudioFocusRequest == null || audioFocusRequest.getPriority() > topAudioFocusRequest.getPriority()) {
topAudioFocusRequest = audioFocusRequest;
}
}
return topAudioFocusRequest;
}
@Override
public void onAudioFocusChange(int focusChange) {
AudioFocusRequest topAudioFocusRequest = getTopAudioFocusRequest();
if (topAudioFocusRequest != null) {
AudioFocusChangeListener audioFocusChangeListener = audioFocusRequests.get(topAudioFocusRequest);
if (audioFocusChangeListener != null) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
audioFocusChangeListener.onAudioFocusChanged(true);
break;
case AudioManager.AUDIOFOCUS_LOSS:
audioFocusRequests.clear();
audioFocusChangeListener.onAudioFocusChanged(false);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
audioFocusChangeListener.onAudioFocusChanged(false);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
audioFocusChangeListener.onAudioFocusChanged(false);
break;
}
}
}
}
public interface AudioFocusChangeListener {
void onAudioFocusChanged(boolean hasAudioFocus);
}
public static class AudioFocusRequest {
private final int priority;
private final AudioAttributes audioAttributes;
public AudioFocusRequest(int priority, AudioAttributes audioAttributes) {
this.priority = priority;
this.audioAttributes = audioAttributes;
}
public int getPriority() {
return priority;
}
public AudioAttributes getAudioAttributes() {
return audioAttributes;
}
public androidx.media.AudioAttributesCompat getAudioAttributesCompat() {
return androidx.media.AudioAttributesCompat.wrap(audioAttributes);
}
public AudioFocusRequestCompat getAudioFocusRequestCompat() {
return new AudioFocusRequestCompat.Builder(getPriority())
.setAudioAttributes(getAudioAttributesCompat())
.build();
}
public AudioFocusRequest getAudioFocusRequest() {
return new AudioFocusRequest.Builder(getPriority())
.setAudioAttributes(audioAttributes)
.build();
}
}
}
このサンプル コードのクラスにはAudioFocusManager
次のメソッドが含まれています。
requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener)
: システムからオーディオ フォーカスを要求し、オーディオ フォーカスの状態が変化したときにアプリケーションに通知するコールバック関数を提供します。このメソッドを複数回呼び出すと、要求の優先順位に基づいて複数のオーディオ フォーカス要求が処理されます。abandonAudioFocus(AudioFocusRequest audioFocusRequest)
:オーディオフォーカスを放棄し、フォーカスを要求しているすべてのオブジェクトのリストを内部的に更新します。updateAudioFocus()
: 現在の優先順位に従ってオーディオ フォーカスを要求しAudioManager
、フォーカス ステータスが変化したときに対応するリスナーに通知するために使用します。getTopAudioFocusRequest()
:最高の優先順位を含むAudioFocusRequest
オブジェクトを返します。- `onオーディオフォーカス
AudioFocusManager
以下は、クラスを使用して複数のオーディオ フォーカス リクエストを処理する完全なコード例です。
public class MainActivity extends AppCompatActivity {
private AudioFocusManager audioFocusManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioFocusManager = new AudioFocusManager(this);
}
@Override
protected void onStart() {
super.onStart();
AudioFocusManager.AudioFocusRequest audioFocusRequest1 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest2 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
audioFocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 开始播放音乐
} else {
// 暂停或停止音乐播放
}
}
});
audioFocusManager.requestAudioFocus(audioFocusRequest2, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 播放通知提示音
} else {
// 停止播放通知提示音
}
}
});
}
@Override
protected void onStop() {
super.onStop();
audioFocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()));
audioFocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()));
}
}
この例では、メソッド内で 2 つの異なるタイプのオーディオ フォーカスMainActivity
を要求します。オブジェクトと は、それぞれメディアの再生音と通知音を表します。また、フォーカス状態の変化を処理するために、各フォーカス要求に対応するものをセットアップします。onStart()
AudioFocusRequest
audioFocusRequest1
audioFocusRequest2
AudioFocusChangeListener
MainActivity
このメソッドではonStop()
、両方のオーディオ フォーカスの解放を要求します。
複数の異なるプレーヤーを同時に管理する必要がある場合 (バックグラウンド ミュージック、サウンド効果、音声プロンプトの再生など)、複数のクラスをインスタンス化できます。各クラスは 1 つのプレーヤーの管理のみを担当しますAudioFocusManager
。AudioFocusManager
複数のインスタンス間のフォーカス要求と変更は独立しているため、適切なタイミングで独自のビジネス ロジックに従って調整する必要があることに注意してください。
3 人のプレーヤーを同時に管理するための簡単なコード例を次に示します。
public class MainActivity extends AppCompatActivity {
private AudioFocusManager mediaPlayer1FocusManager;
private AudioFocusManager mediaPlayer2FocusManager;
private AudioFocusManager mediaPlayer3FocusManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayer1FocusManager = new AudioFocusManager(this);
mediaPlayer2FocusManager = new AudioFocusManager(this);
mediaPlayer3FocusManager = new AudioFocusManager(this);
}
@Override
protected void onStart() {
super.onStart();
AudioFocusManager.AudioFocusRequest audioFocusRequest1 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest2 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest3 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
mediaPlayer1FocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 开始播放媒体音乐
} else {
// 暂停或停止媒体音乐播放
}
}
});
mediaPlayer2FocusManager.requestAudioFocus(audioFocusRequest2, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 开始播放游戏音效
} else {
// 停止播放游戏音效
}
}
});
mediaPlayer3FocusManager.requestAudioFocus(audioFocusRequest3, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 开始播放语音提示
} else {
// 停止播放语音提示
}
}
});
}
@Override
protected void onStop() {
super.onStop();
mediaPlayer1FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()));
mediaPlayer2FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()));
mediaPlayer3FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()));
}
}
この例では、AudioFocusManager
3 つの異なるプレーヤーを順番に処理するために 3 つのオブジェクトをインスタンス化します。各プレーヤーには独自のフォーカス要求と、対応するフォーカス状態リスナーがあります。この方法ではonStart()
、これら 3 つのフォーカス マネージャーを通じてさまざまなオーディオ フォーカスを要求しました。このメソッドではonStop()
、3 つの異なるサウンドのリリースをリクエストします。
前の例でカプセル化されたオーディオ ファイルを使用してAudioPlayer
オーディオ ファイルを再生する場合は、次のように変更できます。
- オブジェクトを作成します
AudioPlayer
。
AudioPlayer audioPlayer = new AudioPlayer();
- オーディオ フォーカスを取得した後、
AudioPlayer
オブジェクトを使用してオーディオ ファイルを再生します。サンプル コードは次のとおりです。 -
mediaPlayer1FocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() { @Override public void onAudioFocusChanged(boolean hasAudioFocus) { if (hasAudioFocus) { // 开始播放媒体音乐 audioPlayer.play(MainActivity.this, R.raw.background_music); } else { // 暂停或停止媒体音乐播放 audioPlayer.stop(); } } });
- オーディオ再生を停止する対応する位置で、
AudioPlayer
オブジェクトのstop()
メソッドを呼び出して、現在再生中のオーディオ ファイルを停止します。 -
audioPlayer.stop();
AudioPlayer
複数のオーディオ ファイルを再生する必要がある場合は、必要に応じて上記の手順を繰り返し、毎回新しいオブジェクトを作成し、対応するメソッドを呼び出します。 -
AudioFocusManager
以下は、以下と組み合わせた完全なコード例です。
public class AudioPlayer implements AudioFocusManager.AudioFocusListener {
private static AudioPlayer instance;
private HashMap<Integer, MediaPlayer> mediaPlayerMap;
private AudioFocusManager audioFocusManager;
private AudioPlayer(Context context) {
mediaPlayerMap = new HashMap<>();
audioFocusManager = new AudioFocusManager(context, this);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void play(Context context, int resId, boolean looping) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
mediaPlayer.setLooping(looping);
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
} else {
MediaPlayer mediaPlayer = MediaPlayer.create(context, resId);
mediaPlayerMap.put(resId, mediaPlayer);
mediaPlayer.setLooping(looping);
mediaPlayer.start();
}
audioFocusManager.requestAudioFocus();
}
public void pause(int resId) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
}
public void stop(int resId) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayerMap.remove(resId);
}
audioFocusManager.abandonAudioFocus();
}
public void stopAll() {
for (MediaPlayer mediaPlayer : mediaPlayerMap.values()) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
mediaPlayerMap.clear();
audioFocusManager.abandonAudioFocus();
}
@Override
public void onAudioFocusGained() {
// do nothing
}
@Override
public void onAudioFocusLost() {
stopAll();
}
@Override
public void onAudioFocusLostTransient() {
stopAll();
}
@Override
public void onAudioFocusLostTransientCanDuck() {
// do nothing
}
}
上記のコードでは、AudioPlayer
シングルトン パターンとして実装し、オーディオ フォーカスを制御するクラスAudioFocusManager
を追加しました。AudioPlayer
このメソッドではplay()
、まずlooping
パラメータに従って、必要なオーディオ MediaPlayer オブジェクトが Map 内に存在するかどうかをクエリします。存在する場合は、ループ再生プロパティを設定して再生を開始します。存在しない場合は、新しい MediaPlayer オブジェクトを作成して Map に追加します。次に、requestAudioFocus()
オーディオ フォーカスをリクエストするメソッドを使用して、オーディオを正常に再生できることを確認します。
stop()
およびメソッドではstopAll()
、まずすべての MediaPlayer オブジェクトを停止し、それらが占有しているリソースを解放します。次に、abandonAudioFocus()
メソッドを使用して、以前に要求したオーディオ フォーカスを返します。
最後に、AudioFocusListener
コールバック メソッドで、さまざまなフォーカス喪失状況に応じて再生を停止します。
AudioFocusManager
これは、と組み合わせたAudioPlayer
完全なコード例です。これがオーディオ プレーヤーの実装に役立つことを願っています。
このクラスを使用してAudioPlayer
オーディオを再生するサンプル コードを次に示します。
public class MainActivity extends AppCompatActivity {
private AudioPlayer audioPlayer;
private int audioResId = R.raw.audio_file;
private boolean isLooping = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioPlayer = AudioPlayer.getInstance(this);
}
public void onClickPlay(View view) {
audioPlayer.play(this, audioResId, isLooping);
}
public void onClickPause(View view) {
audioPlayer.pause(audioResId);
}
public void onClickStop(View view) {
audioPlayer.stop(audioResId);
}
public void onClickStopAll(View view) {
audioPlayer.stopAll();
}
}
上記のコードでは、まずメソッドでインスタンスonCreate()
を取得します。次に、さまざまなボタンをクリックするなどのユーザー操作を処理するときに、クラス内の対応するメソッドをAudioPlayer
呼び出して、オーディオを再生、一時停止、または停止します。AudioPlayer
ユーザーが「再生」ボタンをクリックすると、play()
オーディオフォーカスを要求し、オーディオを再生するメソッドを使用します。ユーザーが「一時停止」ボタンをクリックすると、pause()
オーディオの再生を一時停止するメソッドを使用します。ユーザーが「停止」ボタンをクリックすると、stop()
音声の再生を停止し、占有されていたリソースを解放するメソッドを使用します。ユーザーが「すべて停止」ボタンをクリックすると、stopAll()
すべての音声の再生を停止し、同時に占有されていたリソースを解放する方式を採用しています。
AudioPlayer
このクラスを利用して音声を再生するサンプルコードです。オーディオ プレーヤー アプリケーションの実装に役立つことを願っています。