I am new in android, I'm working on a game app and I want to play Music in background, the music has to be played in all activitys. In addition, I am taking the songs from the user's device and present them in a ListView. The user chooses a song in the ListMusic Activity, then he go on to others Activity and my purpose is that the music will continue in the background.
I hope you understood the process, I added the JAVA also.
Now, I've got this error:
Activity com.example.summerproject.FirstActivity has leaked ServiceConnection com.example.summerproject.ListMusic$1@42116d20 that was originally bound here
From what I understood, the problem is that I am not UnBind the connection on onDestroy() of each activity. Someone know how to fix it? I want the music to continue over all the activitys so it might be a problem to unBind the Service each time.
MusicService:
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener
{
private MediaPlayer player; //media player
private ArrayList<Song> valuesList; //songs List
private int songPosn; //current position
private final IBinder musicBind = new MusicBinder();
public void onCreate()
{
super.onCreate();
songPosn=0;
player= new MediaPlayer();
initMusicPlayer();
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
@Override
public IBinder onBind(Intent intent)
{
//בעת התחברות
return musicBind;
}
@Override
public boolean onUnbind(Intent intent)
{
player.stop();
player.release();
return false;
}
public void initMusicPlayer()
{
//set player properties
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
public void playSong()
{
if(player != null) //אם נוצר כבר
player.reset();
Song songToPlay = valuesList.get(songPosn);
long songId = songToPlay.getId();
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
songId);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e)
{
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.setLooping(true);
player.prepareAsync();
}
public void setList(ArrayList<Song> theSongs){
valuesList=theSongs;
}
public class MusicBinder extends Binder
{
MusicService getService()
{
return MusicService.this;
}
}
public void setSong(int songIndex)
{
songPosn=songIndex;
}
@Override
public void onPrepared(MediaPlayer mp)
{
// TODO Auto-generated method stub
mp.start();
}
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
}
ListActivity( the user chooses songs from here):
public class ListMusic extends Activity implements OnItemClickListener
{
private static ArrayList<Song> valuesList;
private ListView list;
private MySongsAdapter songAdt;
private static MusicService MusicService;
private Intent playIntent;
private static boolean musicBound=false;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
list = (ListView)findViewById(R.id.song_list);
valuesList = new ArrayList<Song>();
getSongList(); //update the valuesList
songAdt = new MySongsAdapter(this, valuesList);
list.setAdapter(songAdt);
list.setOnItemClickListener(this);
}
//connect to the service
public static ServiceConnection musicConnection= new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
MusicBinder binder = (MusicBinder)service;
//get service
MusicService = binder.getService();
// Toast.makeText(getApplicationContext(), "Music Service Is Not Null", Toast.LENGTH_LONG).show();
//pass list
MusicService.setList(valuesList);
musicBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
@Override
protected void onStart()
{
//
super.onStart();
Toast.makeText(getApplicationContext(), "Start", Toast.LENGTH_LONG).show();
if(playIntent ==null)
{
playIntent = new Intent(this, MusicService.class);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
}
}
public void songPicked(View view, int position)
{
//כאשר שיר נבחר
MusicService.setSong(position);
MusicService.playSong();
}
public void getSongList()
{
//אחזור רשימת השירים מהמכשיר
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
long thisId;
int titleColumn, idColumn, artistColumn;
String thisTitle, thisArtist;
if(musicCursor!=null && musicCursor.moveToFirst())
{
//get columns
titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
//add songs to list
while (musicCursor.moveToNext())
{
thisId = musicCursor.getLong(idColumn);
thisTitle = musicCursor.getString(titleColumn);
thisArtist = musicCursor.getString(artistColumn);
valuesList.add(new Song(thisId, thisTitle, thisArtist));
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
//באירוע של לחיצה על שיר
songPicked(view, position);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.music, menu);
return true;
}
@Override
public boolean onOptionsItemSelected (MenuItem item)
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id= item.getItemId();
switch(id)
{
case R.id.btnExit:
stopService(playIntent);
MusicService=null;
finish();
break;
}
return true;
}
The connection to MainActivity:
playIntent = new Intent(this, MusicService.class);
bindService(playIntent, ListMusic.musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
Please, if anyone has an idea what is the problem, I would be grateful!
I want the music to continue over all the activitys so it might be a problem to unBind the Service each time.
This is only a problem because you do this
@Override
public boolean onUnbind(Intent intent)
{
player.stop();
player.release();
return false;
}
Now, every time something calls unbindService()
, the music stops. It is fine to call unbindService()
in an activity's onDestroy()
or onPause()
, but then you should not stop the player in the onUnbind()
method in the service.
You could give the service a public static method that you can call when you ned to stop the music instead:
@Override
public boolean onUnbind(Intent intent)
{
return false;
}
public static void stopPlayMusic()
{
player.stop();
player.release();
}
This way the music will keep on playing even if something unbinds from your service, while still having a way to stop the music from playing. To make this work, you have to make the player
a static variable as well.