2017-10-23 3 views
0

Ich erstelle eine Schleife, die durch eine Zeichenfolge iteriert und abhängig vom vorhandenen Zeichen einen anderen Klang abspielt. Leider wartet es nicht darauf, dass der Sound endet, bevor er fortfährt, was zu Fehlern beim Mediaplayer führt. meine Schleife sieht wie folgt aus:Warten Sie, bis der Sound beendet ist, bevor Sie fortfahren.

for (char ch : morsechars) { 
      if (Character.toString(ch).equals(".")) { 
       Log.d("play: ", "dot"); 
       try { 
        startPlayback(); 
       } catch (Exception e){ 
        e.printStackTrace(); 
       } 
      } else if (Character.toString(ch).equals("-")){ 
       Log.d("play: ", "dash"); 
       try { 
        startPlayback(); 
       } catch (Exception e){ 
        e.printStackTrace(); 
       } 
      } 
     } 

und meine Spieler sieht wie folgt aus:

public void startPlayback() throws Exception{ 
     play = MediaPlayer.create(this, dotFILE); 
     play.start(); 
     isplaying = true; 
     while (isplaying == true){ 

     } 


     play.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
      public void onCompletion(MediaPlayer play) { 
       isplaying = false; 
       play.stop(); 
       play.reset(); 
       play.release(); 
      } 
     }); 
    } 

Ich bin nicht sicher, wie für den Abschluss Hörer warten, bevor sie in der Schleife zum nächsten Zeichen weitergehen.

Antwort

1

1) MediaPlayer ist nicht das richtige Werkzeug für diesen Job. Schauen Sie sich SoundPool an. Es ist für kurze Sounds vorgesehen, die wiederholt abgespielt werden.

2) Für Ihren Fall, was Sie wollen, ist nicht wirklich eine Schleife. Die Sounds werden asynchron gespielt, so dass Sie in die Situation geraten, in der sich die Calls aufeinander stapeln. Das führt dazu, dass der native Code von MediaPlayer die verfügbaren Ressourcen erschöpft.

Was Sie wollen, ist eine Reihe von Rückrufen. Die MediaPlayer hat den Completion Callback, den Sie bereits verwenden, aber das scheint genau das zu sein, was benötigt wird, aber für Ihren Anwendungsfall reicht es nicht aus. Der systemeigene Code für MediaPlayer wird nicht in der Lage sein, seine Ressourcen schnell genug für jeden nachfolgenden Aufruf freizugeben, und die gleiche Erschöpfung der Ressourcen wird auftreten. Das ist nur eine unglückliche Realität für die Funktionsweise der MediaPlayer.

SoundPool hat nicht diesen bequemen Abschluss Callback, aber in diesem Fall haben Sie wahrscheinlich nur zwei Klangbeispiele und Sie wissen, wie lange sie sind. Eine einfache Timer-Verzögerung wird wahrscheinlich ausreichen. Sie können Handler.postDelayed verwenden, um diesen Effekt zu erzielen. In jedem Callback-Event spielen Sie einfach den nächsten Sound, fahren Sie mit der von Ihnen verwendeten Variable fort, um den aktuellen Sound zu verfolgen, und posten Sie denselben Callback erneut, um alle verbleibenden Sounds abzuspielen. Es ist eine Art asynchrone Schleife.

UPDATE

um zu verstehen, was los ist, hier ist ein wenig aus der Dokumentation des Android auf Handler:

Ein Handler ermöglicht es Ihnen, Nachrichten- und Runnable Objekte zu senden und Verfahren mit einem Message Thread zugeordnet ist. Jede Handler-Instanz ist einem einzelnen Thread und der Nachrichtenwarteschlange dieses Threads zugeordnet. Wenn Sie einen neuen Handler erstellen, wird er an die Thread-/Nachrichtenwarteschlange des Threads gebunden, der ihn erstellt. Ab diesem Zeitpunkt werden Nachrichten und Runnables an diese Nachrichtenwarteschlange übergeben und ausgeführt, sobald sie aus der Nachricht kommen Warteschlange.

Also, wenn meine Vermutung über Ihre Code-Struktur nahe zu korrigieren, würden Sie ein Handler Objekt als Mitglied Ihrer Activity Klasse erstellen. Dadurch wird es an den GUI-Thread gebunden, was in Ordnung sein sollte, da Sie dort nicht viel arbeiten werden. Sie benötigen auch eine Runnable, um als die Aufgabe zu fungieren, die gepostet wird. Machen Sie es auch zu einem Mitglied Ihrer Klasse. Und Sie werden Ihre String brauchen, die die Charaktere enthält, um ein Mitglied zu sein. Und Sie benötigen eine int, um zu verfolgen, welcher Charakter Sie gerade sind.

private Handler playMorseHandler = new Handler(); 
private String morseChars = ".--...---"; // I don't know where you set this 
private int charIndex = 0; 
private Runnable playMorseTask = new Runnable() { 
    if (morseChars == null || 
     charIndex < 0 || 
     charIndex >= morseChars.length()) { 
     Log.w("whateverTag", "Basic assumptions failed"); 
     return; 
    } 
    char ch = morseChars.charAt(charIndex); 
    long lengthOfClip = 0L; 
    boolean postAgain = true; 
    if (ch == '.') { 
     Log.d("play: ", "dot"); 
     lengthOfClip = 300L; // I don't know how long your clips are 
     try { 
      startPlayback(); 
     } catch (Exception e){ 
      e.printStackTrace(); 
     } 
    } else if (ch == '-') { 
     Log.d("play: ", "dash"); 
     lengthOfClip = 500L; // I don't know how long your clips are 
     try { 
      startPlayback(); 
     } catch (Exception e){ 
      e.printStackTrace(); 
     } 
    } else { 
     Log.d("whateverTag", "unexpected input"); 
     postAgain = false; 
    } 
    ++charIndex; 
    if (postAgain && charIndex < morseChars.length()) { 
     playMorseHandler.postDelayed(this, lengthOfClip); 
    } 
}; 

Überall dort, wo Sie die Klänge zu spielen beginnen möchten, rufen Sie einfach:

charIndex = 0; 
playMorseHandler.post(playMorseTask); 

Das einzige, was wäre bei Ihrer startPlayback() Methode das Richtige zu tun, machen, die SoundPool zu verwenden anstelle von MediaPlayer. Das liegt daran, dass, wie ich bereits erwähnt habe, MediaPlayer unweigerlich dazu führen wird, dass dem System Ressourcen ausgehen, die diese kurzen Töne so schnell zusammen spielen.

+0

Ive sah sich um, aber kann nicht herausfinden, wie man den einfachen Handler.postDelayed implementiert, können Sie ein Codebeispiel bereitstellen? –

+0

Der Code ive versucht scheint zu arbeiten und Verzögerungen vor dem Ausführen des Codes, aber die Schleife wartet nicht. Ich bin mir nicht sicher, wie ich es wiederholen soll, so dass ich eine Menge Zeit warten kann, bevor ich fortfahre. @Dave –

+0

Ich wollte, dass Sie überhaupt keine for-Schleife verwenden. Es ist nicht das richtige Konstrukt zu verwenden. Stattdessen müssen Sie einen Callback verwenden, der sich selbst als Looping-Mechanismus bezeichnet. Ich werde meine Antwort in Kürze aktualisieren, um zu zeigen, was ich meine, aber ich weiß nicht annähernd genug über Ihr Projekt, um etwas zu liefern, das einfach funktionieren wird. Sie müssen es testen und versuchen, einige Dinge selbst zu erledigen. – Dave

Verwandte Themen