2013-02-24 3 views
6

Ich habe ein Problem mit dem folgenden Code. Ich habe setPrevNextListener auf meinem MediaController aufgerufen und zwei onClickListeners für Prev und Next definiert. Wenn ich auf den nächsten Knopf klicke, anstatt einen Titel vorwärts zu gehen, gehe ich zwei Titel vor. Dies scheint darauf zurückzuführen zu sein, dass onCompletion irgendwie aufgerufen wird. Ruft MediaPlayer.reset() onCompletion auf? Ich habe logcat Ausgabe und meinen Code eingeschlossen. Lass es mich wissen, wenn ich etwas falsch mache. Danke im Voraus.Android MediaPlayer.reset() ruft onCompletion

Logcat:

02-24 00:36:34.826: D/MP(6675): Next Button Clicked, index was: 0 
02-24 00:36:34.837: D/MP(6675): About to call Reset() 
02-24 00:36:34.906: D/MP(6675): Inside setUpPlayer 
02-24 00:36:34.917: D/MP(6675): Called setDataSource with index: 1 
02-24 00:36:34.917: D/MP(6675): Leaving setUpPlayer 
02-24 00:36:34.917: D/MP(6675): About to call prepareAsync() 
02-24 00:36:34.937: D/MP(6675): Leaving next button 
02-24 00:36:35.226: E/MediaPlayer(6675): Attempt to call getDuration without a valid mediaplayer 
02-24 00:36:35.226: E/MediaPlayer(6675): error (-38, 0) 
02-24 00:36:35.276: E/MediaPlayer(6675): Error (-38,0) 
02-24 00:36:35.287: D/MP(6675): Inside onCompletion 
02-24 00:36:35.337: D/MP(6675): About to call Reset() 
02-24 00:36:35.347: D/MP(6675): Inside setUpPlayer 
02-24 00:36:35.356: D/MP(6675): Called setDataSource with index: 2 
02-24 00:36:35.356: D/MP(6675): Leaving setUpPlayer 
02-24 00:36:35.356: D/MP(6675): About to call prepareAsync() 
02-24 00:36:35.377: D/MP(6675): Leaving onCompletion 
02-24 00:36:36.517: D/MP(6675): Inside onPrepared, index is: 2 
02-24 00:36:36.577: D/MP(6675): Leaving onPrepared 

Code:

public class MusicPlayerActivity extends Activity implements OnPreparedListener, OnCompletionListener, MediaController.MediaPlayerControl { 

    private MediaPlayer mp; 
    private MediaController mc; 
    private SonarDatabase db; 
    private SubsonicAPIConnector sonic; 
    ArrayList<String> songs; 
    int index = 0; 
    private Handler handler = new Handler(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.music_player); 

     // Get params from intent 
     Intent i = getIntent(); 
     String albumId = i.getStringExtra("albumId"); 
     String artistId = i.getStringExtra("artistId"); 
     String albumName = i.getStringExtra("albumName"); 
     String songName = i.getStringExtra("songName"); 
     String songId = i.getStringExtra("songId"); 
     String coverArt = "al-"+albumId+".jpeg"; 
     String duration = i.getStringExtra("duration"); 
     Log.d("MP", "results: albumName:" + albumName + ", songName: " + songName + ", songId: " 
       + songId + ", duration: " + duration + ", coverArt: " + coverArt + ", artistId: " 
       + artistId + ", albumId: " + albumId); 
     db = new SonarDatabase(getApplicationContext()); 
     sonic = new SubsonicAPIConnector(db.getURL(), db.getUsername(), db.getPassword()); 
     String artistName = db.getArtistNameById(artistId); 
     setTitle("Now Playing"); 
     songs = db.getSongListForAlbum(albumId); 
     index = songs.indexOf(songId); 
     Log.d("MP", "songid: " + songId + ", index: " + index); 
     // Update text views with song information 
     TextView txtArtist = (TextView) findViewById(R.id.txtArtistName); 
     txtArtist.setText(artistName); 
     TextView txtAlbum = (TextView) findViewById(R.id.txtAlbumName); 
     txtAlbum.setText(albumName); 
     TextView txtSong = (TextView) findViewById(R.id.txtSongName); 
     txtSong.setText(songName); 

     // Show the album art 
     File img = new File(this.getFilesDir()+"/covers/"+coverArt); 
     if(img.exists()) { 
      Log.d("MP", "Found image at: " + img.toString()); 
      ImageView imgView = (ImageView) findViewById(R.id.cover_art); 
      imgView.setImageBitmap(BitmapFactory.decodeFile(img.getPath())); 
     } else { 
      Log.d("MP", "Couldn't find image: " + img.toString()); 
     } 


     // Create the media player and controller 
     mp = new MediaPlayer(); 
     mp.setOnPreparedListener(this); 
     mp.setOnCompletionListener(this); 
     mc = new NonHidingMediaController(this); 
     mc.setPrevNextListeners(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // next button clicked 
       Log.d("MP", "Next Button Clicked, index was: " + index); 
       playNextTrack(); 
       Log.d("MP", "Leaving next button"); 
      } 
     }, new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // previous button clicked 
       Log.d("MP", "Previous button clicked, index was: " + index); 
       if(mp.isPlaying() && mp.getCurrentPosition() < 2000 && index != 0) { 
        Log.d("MP", "Start the prior song."); 
        playPreviousTrack(); 
       } else { 
        Log.d("MP", "Restart this song."); 
        restartCurrentTrack(); 
       } 
       Log.d("MP", "Leaving previous button"); 
      } 
     }); 
     mc.setMediaPlayer(this); 
     setUpPlayer(); 
     Log.d("MP", "About to call prepareAsync()"); 
     mp.prepareAsync(); 
    } 

    @Override 
    public void onCompletion(MediaPlayer mp) { 
     Log.d("MP", "Inside onCompletion"); 
     //TODO add code for scrobbling here. 
     playNextTrack(); 
     Log.d("MP", "Leaving onCompletion"); 
    } 


    private void playNextTrack() { 
     index++; 
     TextView txtSong = (TextView) findViewById(R.id.txtSongName); 
     txtSong.setText(db.getSongNameById(songs.get(index))); 
     Log.d("MP", "About to call Reset()"); 
     mp.reset(); 
     setUpPlayer(); 
     Log.d("MP", "About to call prepareAsync()"); 
     mp.prepareAsync(); 
    } 

    private void playPreviousTrack() { 
     index--; 
     TextView txtSong = (TextView) findViewById(R.id.txtSongName); 
     txtSong.setText(db.getSongNameById(songs.get(index))); 
     Log.d("MP", "About to call Reset()"); 
     mp.reset(); 
     setUpPlayer(); 
     Log.d("MP", "About to call prepareAsync()"); 
     mp.prepareAsync(); 

    } 

    private void restartCurrentTrack() { 
     mp.seekTo(0); 
    } 

    public void onPrepared(MediaPlayer mp) { 
     Log.d("MP", "Inside onPrepared, index is: " + index); 
     mc.setMediaPlayer(this); 
     mc.setAnchorView(findViewById(R.id.music_player_view)); 
     mp.start(); 
     handler.post(new Runnable() { 
      public void run() { 
       mc.setEnabled(true); 
       mc.show(); 
      } 
     }); 
     Log.d("MP", "Leaving onPrepared"); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.activity_music_player, menu); 
     return true; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     Log.d("MP", "OnTouchEvent called"); 
     mc.show(); 
     return false; 
    } 

    private void setUpPlayer() { 
     Log.d("MP", "Inside setUpPlayer"); 
     mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
     try { 
      mp.setDataSource(sonic.streamString("&id=" + songs.get(index))); 
      Log.d("MP", "Called setDataSource with index: " + index); 
     } catch (IllegalArgumentException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (SecurityException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IllegalStateException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     Log.d("MP", "Leaving setUpPlayer"); 
    } 

    @Override 
    protected void onStop() { 
     super.onStop(); 
     mc.hide(); 
     mp.stop(); 
     mp.release(); 
    } 

    public void start() { 
     mp.start(); 
    } 

    public void pause() { 
     mp.pause(); 
    } 

    public int getDuration() { 
     return mp.getDuration(); 
    } 

    public int getCurrentPosition() { 
     return mp.getCurrentPosition(); 
    } 

    public void seekTo(int i) { 
     mp.seekTo(i); 
    } 

    public boolean isPlaying() { 
     return mp.isPlaying(); 
    } 

    public int getBufferPercentage() { 
     return 0; 
    } 

    public boolean canPause() { 
     return true; 
    } 

    public boolean canSeekBackward() { 
     return true; 
    } 

    public boolean canSeekForward() { 
     return true; 
    } 

    public class NonHidingMediaController extends MediaController { 
     public NonHidingMediaController(Context context, AttributeSet attrs) { 
      super(context, attrs); 
     } 

     public NonHidingMediaController(Context context, boolean useFastForward) { 
      super(context, useFastForward); 
     } 

     public NonHidingMediaController(Context context) { 
      super(context); 
     } 

     @Override 
     public void show(int timeout) { 
      super.show(0); 
     } 

    } 


} 
+0

Ich denke, Onclick werden zweimal genannt, können Sie überprüfen, ob pelase Onclick zweimal genannt zu werden? –

+0

Onclick wird nicht zweimal aufgerufen. Wenn das der Fall wäre, wären mehrere Meldungen in der Log-Datei: Next Button Clicked, ... – cjackson

+0

ok fine.so ru bekommen onCompletion immer auf Klick von nächsten, ich denke, Ihre Vermutung ist richtig, es wird bcoz wie beim Klicken aufgerufen Als nächstes wird das aktuelle Spiel abgeschlossen sein. –

Antwort

22

Ich habe ein wenig durch die Android-Quelle zu graben und fand, dass alle nicht behandelten Fehler Mediaplayer verursachen die onCompletion Handler aufzurufen. In diesem Fall scheinen Sie getDuration in den Status "Leerlauf", "Initialisiert" oder "Fehler" aufzurufen. Möglich von innerhalb des Media Controllers. Ich würde vorschlagen, etwas Log.d() direkt vor irgendwelchen Orten hinzuzufügen, die getDuration aufrufen, um zu sehen, wo der Anruf das Problem verursacht.

+0

Danke dafür - du hast Recht. IMO das ist ziemlich komisches Verhalten. Ich verstehe, dass sie wahrscheinlich über die Ereignisausbreitung nachgedacht haben, aber es ist merkwürdig, dass ein Mangel an einem Fehler-Listener bewirkt, dass diese in einen unabhängigen Listener "überlaufen". – mszaro

+1

Ja, es ist unerwartet. Aber nachdem ich das gelesen hatte, ging ich in die Dokumentation und sicher, dass es dort dokumentiert ist: "Wenn man falsch zurückgibt oder überhaupt keinen OnErrorListener hat, wird der OnCompletionListener aufgerufen." http://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener.html#onError(android.media.MediaPlayer,%20int,%20int) –

3

MediaPlayer.OnErrorLisener hinzufügen und return true von der Methode overrided

mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 
        @Override 
        public boolean onError(MediaPlayer mp, int what, int extra) { 
         return true; 
        } 
       }); 
+0

Du hast mir den Chef gerettet :) – VickyS

Verwandte Themen