今日は一日中、この問題の回避策を探していましたが、他の日は何時間もかかりました。しかし、今日は少なくとも問題を改善することができました。
ヘッダーがめちゃくちゃな .acc オーディオ ファイルがあります。それを呼び出し"BadFile"
てみましょう。
プレイリストを表すファイルの配列リストと、特定の瞬間に再生する曲を定義する int ポインターがあります。プレイリストでいくつかの曲をキューに入れると、GoodFile1、GoodFile2、BadFile、GoodFile3、GoodFile4 などとしましょう。ポインターを 0 に設定すると、GoodFile1 の再生が開始されます。
//これは Thread.currentThread().getId() == 1 から呼び出されます
private void play() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
playCicle();
}
});
t.start();
}
private synchronized void playCicle() {
Log.e("THREAD" , "T:" + Thread.currentThread().getId());
Log.e("TRYING TO PLAY", playlist.get(playPointer).getFile().getAbsolutePath());
try {
if(progressSenderRunnable != null) {
progressSenderRunnable.stop();
}
if(myMP != null) {
myMP.release();
}
myMP = new MediaPlayer();
myMP.setAudioStreamType(AudioManager.STREAM_MUSIC);
myMP.setDataSource(mService, Uri.parse(Uri.encode(playlist.get(playPointer).getFile().getAbsolutePath())));
setOnPrepareListener();
myMP.prepare();
setOnCompletionListener();
setOnErrorListener();
myMP.start();
sendImPlaying();
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (SecurityException e) {
e.printStackTrace();
return;
} catch (IllegalStateException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
Log.e("METHOD " , "EXITING");
}
private void setOnCompletionListener() {
myMP.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
Log.e("onCompletionthread" , "T: "+Thread.currentThread().getId());
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if(!userSetPlayPointerNext && !userSetPlayPointerPrevious) {
playPointer++;
}
userSetPlayPointerNext = false;
userSetPlayPointerPrevious = false;
if(playPointer < playlist.size()) {
play();
}
else {
if(progressSenderRunnable != null) {
progressSenderRunnable.stop();
}
if(myMP != null) {
myMP.release();
}
sendImStopped();
}
}
});
t.start();
}
});
}
最初の曲の再生を開始したら、次のボタンをクリックすると、ID 1 のスレッドによってこの次のメソッドが呼び出されます。
void playNextSong() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if(isPlaying() && playPointer < playlist.size() - 1) {
playPointer++;
userSetPlayPointerNext = true;
myMP.seekTo(myMP.getDuration() - 1);
}
}
});
t.start();
}
GoodFile2 の再生が始まりました。次に、次のボタンをスパムし始め、UI がハングします。このハングの後、次のボタンを問題なくスパムすることができます (BadFile を通過したため)。
10-17 21:18:23.734: E/THREAD(24021): T:41
10-17 21:18:23.734: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/01_Compay Segundo - Te Apartes De Mi.mp3
10-17 21:18:23.744: E/METHOD(24021): EXITING
10-17 21:18:23.744: E/PREPARED(24021): PREPARED
10-17 21:18:24.364: E/Service rcv(24021): 17
10-17 21:18:24.364: E/back in handler(24021): 1
10-17 21:18:24.384: E/onCompletionthread(24021): T: 1
10-17 21:18:24.384: E/THREAD(24021): T:45
10-17 21:18:24.384: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/02 - Blue.aac
10-17 21:18:24.394: E/METHOD(24021): EXITING
10-17 21:18:24.724: E/PREPARED(24021): PREPARED
10-17 21:18:28.914: E/onCompletionthread(24021): T: 1
10-17 21:18:28.924: E/THREAD(24021): T:48
10-17 21:18:28.924: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/02_Ibrahím Ferrer - Ay Candela.mp3
10-17 21:18:28.944: E/METHOD(24021): EXITING
10-17 21:18:29.074: E/PREPARED(24021): PREPARED
10-17 21:18:23.734 で、ID 41 のスレッドによって GoodFile1 がほとんど再生されていることがわかります。
場所: 10-17 21:18:24.364: サービスが の op_code を受信していることがわかりますplayNextSong()
。
At: 10-17 21:18:24.364:: への呼び出しからメインスレッドが戻っているのを見ることができますplayNextSong()
一方、ID 45 のスレッドは BadFile をロードし、playNextSong()
メソッドを終了します。
ここにハングがあります:
10-17 21:18:24.724: E/準備済み (24021): 準備済み
10-17 21:18:28.914: E/onCompletionthread (24021): T: 1
この 4 秒間、私の UI は使用できません。私が見ているのは、setOnCompletionリスナーがメインスレッドから呼び出されなかったとしても、リスナーの呼び出しで呼び出されるメインスレッドですが、これがハングに関連しているかどうかはわかりません。
現時点では不必要なスレッドが多すぎるかもしれませんが、できるだけメインスレッドから離れてほとんどの作業を完了させようとしていました. 将来これを変更します。
また、次の曲を再生するために新しいスレッドを開始するために on completionListener を使用しているため、同期キーワードは現時点では役に立たないと思います。
誰かが私が間違っていることを知っていて、それが私にそれらの4を払わせているなら、私は大いに感謝します!
編集:
私が話していたコンソール ダンプを見つけると、この警告はパッケージの logcat フィルターに表示されません。
10-18 07:46:37.055: E/THREAD(10772): T:21
10-18 07:46:37.055: E/TRYING TO PLAY(10772): /mnt/sdcard/Music/BadFileTest/02 - Blue.aac
10-18 07:46:37.075: I/StagefrightPlayer(157): setDataSource('/mnt/sdcard/Music/BadFileTest/02 - Blue.aac')
10-18 07:46:37.625: V/OMXCodec(157): Attempting to allocate OMX node 'OMX.Nvidia.aac.decoder'
10-18 07:46:37.625: V/OMXCodec(157): Attempting to allocate OMX node 'OMX.TI.AAC.decode'
10-18 07:46:37.625: V/OMXCodec(157): Successfully allocated software codec 'AACDecoder'
10-18 07:46:37.625: E/PREPARED(10772): PREPARED
10-18 07:46:37.625: E/start(10772): before
10-18 07:46:37.625: W/AACDecoder(157): Sample rate was 44100 Hz, but now is 0 Hz
10-18 07:46:37.625: E/start(10772): after
10-18 07:46:37.635: W/AACDecoder(157): Disable AAC+/eAAC+ since upsampling factor is 1
10-18 07:46:37.635: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.635: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
不思議なことに、このコーデック エラーの警告は、メイン スレッドがハングしている時間だけ、約 4 秒間表示されます。