0

Ich versuche, einen Android-Musik-Player App in github.com/spragucm/MusicPlayerE/Window: android.view.WindowLeaked Fehler

wie beschrieben zu bauen Während ich in der Lage bin, Musik zu spielen, auf das Spieler-Symbol aus Infobereich klicken, ich bin Fehler erhalten

E/WindowManager: android.view.WindowLeaked: .MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView. 

Der Fehler wird beim Aufrufen von MediaController.show() nach dem Aufruf des Players aus dem Benachrichtigungsfach ausgelöst.

Ich habe viel Zeit in SO verbracht, um verschiedene ähnliche Fragen durchzugehen, aber nichts passt zu meinem Szenario. Jede Hilfe wird sehr geschätzt. Vielen Dank.

Hauptaktivität:

public class MainActivity extends Activity implements MediaPlayerControl { 

    //song list variables 
    private ArrayList<Song> songList; 
    private ListView songView; 

    //service 
    private MusicService musicSrv; 
    private Intent playIntent; 
    //binding 
    private boolean musicBound=false; 

    //controller 
    private MusicController controller; 

    //activity and playback pause flags 
    private boolean paused=false, playbackPaused=false; 

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

     //retrieve list view 
     songView = (ListView)findViewById(R.id.song_list); 
     //instantiate list 
     songList = new ArrayList<Song>(); 
     //get songs from device 
     getSongList(); 
     //sort alphabetically by title 
     Collections.sort(songList, new Comparator<Song>(){ 
      public int compare(Song a, Song b){ 
       return a.getTitle().compareTo(b.getTitle()); 
      } 
     }); 
     //create and set adapter 
     SongAdapter songAdt = new SongAdapter(this, songList); 
     songView.setAdapter(songAdt); 

     //setup controller 
     setController(); 
    } 

    //connect to the service 
    private ServiceConnection musicConnection = new ServiceConnection(){ 

     @Override 
     public void onServiceConnected(ComponentName name, IBinder service) { 
      MusicBinder binder = (MusicBinder)service; 
      //get service 
      musicSrv = binder.getService(); 
      //pass list 
      musicSrv.setList(songList); 
      musicBound = true; 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName name) { 
      musicBound = false; 
     } 
    }; 

    //start and bind the service when the activity starts 
    @Override 
    protected void onStart() { 
     super.onStart(); 
     if(playIntent==null){ 
      playIntent = new Intent(this, MusicService.class); 
      bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE); 
      startService(playIntent); 
     } 
    } 

    //user song select 
    public void songPicked(View view){ 
     musicSrv.setSong(Integer.parseInt(view.getTag().toString())); 
     musicSrv.playSong(); 
     if(playbackPaused){ 
      setController(); 
      playbackPaused=false; 
     } 
     controller.show(0); 
    } 

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

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     //menu item selected 
     switch (item.getItemId()) { 
     case R.id.action_shuffle: 
      musicSrv.setShuffle(); 
      break; 
     case R.id.action_end: 
      stopService(playIntent); 
      musicSrv=null; 
      System.exit(0); 
      break; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    //method to retrieve song info from device 
    public void getSongList(){ 
     //query external audio 
     ContentResolver musicResolver = getContentResolver(); 
     Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 
     Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null); 
     //iterate over results if valid 
     if(musicCursor!=null && musicCursor.moveToFirst()){ 
      //get columns 
      int titleColumn = musicCursor.getColumnIndex 
        (android.provider.MediaStore.Audio.Media.TITLE); 
      int idColumn = musicCursor.getColumnIndex 
        (android.provider.MediaStore.Audio.Media._ID); 
      int artistColumn = musicCursor.getColumnIndex 
        (android.provider.MediaStore.Audio.Media.ARTIST); 
      //add songs to list 
      do { 
       long thisId = musicCursor.getLong(idColumn); 
       String thisTitle = musicCursor.getString(titleColumn); 
       String thisArtist = musicCursor.getString(artistColumn); 
       songList.add(new Song(thisId, thisTitle, thisArtist)); 
      } 
      while (musicCursor.moveToNext()); 
     } 
    } 

    //set the controller up 
    private void setController(){ 
     controller = new MusicController(this); 
     //set previous and next button listeners 
     controller.setPrevNextListeners(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       playNext(); 
      } 
     }, new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       playPrev(); 
      } 
     }); 
     //set and show 
     controller.setMediaPlayer(this); 
     controller.setAnchorView(findViewById(R.id.song_list)); 
     controller.setEnabled(true); 
    } 

    private void playNext(){ 
     musicSrv.playNext(); 
     if(playbackPaused){ 
      setController(); 
      playbackPaused=false; 
     } 
     controller.show(0); 
    } 

    private void playPrev(){ 
     musicSrv.playPrev(); 
     if(playbackPaused){ 
      setController(); 
      playbackPaused=false; 
     } 
     controller.show(0); 
    } 

    @Override 
    protected void onResume(){ 
     super.onResume(); 
     if(paused){ 
      setController(); 
      paused=false; 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     stopService(playIntent); 
     musicSrv=null; 
     super.onDestroy(); 
    } 
} 

Musik-Controller:

public class MusicController extends MediaController { 

    public MusicController(Context c){ 
     super(c); 
    } 

    public void hide(){} 

} 

Music Service:

public class MusicService extends Service implements 
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, 
MediaPlayer.OnCompletionListener { 

    //media player 
    private MediaPlayer player; 
    //song list 
    private ArrayList<Song> songs; 
    //current position 
    private int songPosn; 
    //binder 
    private final IBinder musicBind = new MusicBinder(); 
    //title of current song 
    private String songTitle=""; 
    //notification id 
    private static final int NOTIFY_ID=1; 
    //shuffle flag and random 
    private boolean shuffle=false; 
    private Random rand; 

    public void onCreate(){ 
     //create the service 
     super.onCreate(); 
     //initialize position 
     songPosn=0; 
     //random 
     rand=new Random(); 
     //create player 
     player = new MediaPlayer(); 
     //initialize 
     initMusicPlayer(); 
    } 

    public void initMusicPlayer(){ 
     //set player properties 
     player.setWakeMode(getApplicationContext(), 
       PowerManager.PARTIAL_WAKE_LOCK); 
     player.setAudioStreamType(AudioManager.STREAM_MUSIC); 
     //set listeners 
     player.setOnPreparedListener(this); 
     player.setOnCompletionListener(this); 
     player.setOnErrorListener(this); 
    } 

    //pass song list 
    public void setList(ArrayList<Song> theSongs){ 
     songs=theSongs; 
    } 

    //binder 
    public class MusicBinder extends Binder { 
     MusicService getService() { 
      return MusicService.this; 
     } 
    } 

    //activity will bind to service 
    @Override 
    public IBinder onBind(Intent intent) { 
     return musicBind; 
    } 

    //release resources when unbind 
    @Override 
    public boolean onUnbind(Intent intent){ 
     player.stop(); 
     player.release(); 
     return false; 
    } 

    //play a song 
    public void playSong(){ 
     //play 
     player.reset(); 
     //get song 
     Song playSong = songs.get(songPosn); 
     //get title 
     songTitle=playSong.getTitle(); 
     //get id 
     long currSong = playSong.getID(); 
     //set uri 
     Uri trackUri = ContentUris.withAppendedId(
       android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
       currSong); 
     //set the data source 
     try{ 
      player.setDataSource(getApplicationContext(), trackUri); 
     } 
     catch(Exception e){ 
      Log.e("MUSIC SERVICE", "Error setting data source", e); 
     } 
     player.prepareAsync(); 
    } 

    //set the song 
    public void setSong(int songIndex){ 
     songPosn=songIndex; 
    } 

    @Override 
    public void onCompletion(MediaPlayer mp) { 
     //check if playback has reached the end of a track 
     if(player.getCurrentPosition()>0){ 
      mp.reset(); 
      playNext(); 
     } 
    } 

    @Override 
    public boolean onError(MediaPlayer mp, int what, int extra) { 
     Log.v("MUSIC PLAYER", "Playback Error"); 
     mp.reset(); 
     return false; 
    } 

    @Override 
    public void onPrepared(MediaPlayer mp) { 
     //start playback 
     mp.start(); 
     //notification 
     Intent notIntent = new Intent(this, MainActivity.class); 
     notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     PendingIntent pendInt = PendingIntent.getActivity(this, 0, 
       notIntent, PendingIntent.FLAG_UPDATE_CURRENT); 

     NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 

     builder.setContentIntent(pendInt) 
     .setSmallIcon(R.drawable.play) 
     .setTicker(songTitle) 
     .setOngoing(true) 
     .setContentTitle("Playing") 
     .setContentText(songTitle); 
     Notification not = builder.build(); 
     startForeground(NOTIFY_ID, not); 
    } 

    //playback methods 
    public int getPosn(){ 
     return player.getCurrentPosition(); 
    } 

    public int getDur(){ 
     return player.getDuration(); 
    } 

    public boolean isPng(){ 
     return player.isPlaying(); 
    } 

    public void pausePlayer(){ 
     player.pause(); 
    } 

    public void seek(int posn){ 
     player.seekTo(posn); 
    } 

    public void go(){ 
     player.start(); 
    } 

    //skip to previous track 
    public void playPrev(){ 
     songPosn--; 
     if(songPosn<0) songPosn=songs.size()-1; 
     playSong(); 
    } 

    //skip to next 
    public void playNext(){ 
     if(shuffle){ 
      int newSong = songPosn; 
      while(newSong==songPosn){ 
       newSong=rand.nextInt(songs.size()); 
      } 
      songPosn=newSong; 
     } 
     else{ 
      songPosn++; 
      if(songPosn>=songs.size()) songPosn=0; 
     } 
     playSong(); 
    } 

    @Override 
    public void onDestroy() { 
     stopForeground(true); 
    } 

    //toggle shuffle 
    public void setShuffle(){ 
     if(shuffle) shuffle=false; 
     else shuffle=true; 
    } 
} 
+0

Veröffentlichen Sie verwandte Codes. – fluffyBatman

+0

Verfolgen Sie, wo von Ihnen "MainActivity" Klasse undicht ist. – azizbekian

+0

@azizbekian Warum hast du das vorgeschlagen? – Adi

Antwort

0

Ihre MusicController Klasse ist ein schöner Kandidat Ihre MainActivity undichter. Sehen Sie sich diese Zeile an:

controller.setMediaPlayer(this); 

Was passiert nach der Änderung der Ausrichtung? Eine neue Aktivität wird erstellt, aber Ihr Controller verweist möglicherweise weiterhin auf die vorherige Aktivität, und der Garbage Collector kann die vorherige Aktivität nicht aus dem Heapspeicher entfernen, wodurch ein Speicherverlust entstehen kann.

Um meine Hypothese zu überprüfen, können Sie Leak Canary installieren, die Ihnen die Ursache der Leckage zeigen wird.

Siehe auch this post für eine andere Arten von Speicherlecks in Android und wie Sie sie überwinden.