I am working on android code that switches between two different activities. There is a service that plays music over both of these activities. The problem is that when i use the back button the service ( the music) stops. I have done research on the topic i have both onResume and onRestart methods in place....i can't figure out what to do next,any help will be greatly appreciated. Both activites and service are listed below.
MainActivity.java
public class MainActivity extends Activity {
MusicService myService;
private boolean isBound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isBound=false;
playAudio();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onButtonClick(View v) {
Intent intent = new Intent(this, Second_activity.class);
startActivity(intent);
onStop();
///Intent i= new Intent(this,EmpireShips.class);
//// startActivity(i);
//// onStop();
}
public void playAudio() {
Intent objIntent = new Intent(this, MusicService.class);
if(!isBound)
{
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
else
{
myService.plauseAudio();
isBound=false;
unbindService(myConnection);
}
}
public void stopAudio(View view) {
Intent objIntent = new Intent(this, MusicService.class);
if(isBound)
{
isBound=false;
unbindService(myConnection);
stopService(objIntent);
}
else
stopService(objIntent);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = ((MusicService.MyLocalBinder) service).getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
unbindService(myConnection);
isBound = false;
}
}
public void onStop(){
super.onStop();
if (isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
unbindService(myConnection);
isBound = false;
myService.plauseAudio();
}
}
Second_activity.java
public class Second_activity extends Activity {
MusicService myService;
private boolean isBound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
isBound=false;
playAudio();
}
public void playAudio() {
Intent objIntent = new Intent(this, MusicService.class);
if(!isBound)
{
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
else
{
myService.plauseAudio();
isBound=false;
unbindService(myConnection);
}
}
public void stopAudio(View view) {
Intent objIntent = new Intent(this, MusicService.class);
if(isBound)
{
isBound=false;
unbindService(myConnection);
stopService(objIntent);
}
else
stopService(objIntent);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = ((MusicService.MyLocalBinder) service).getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
unbindService(myConnection);
isBound = false;
}
}
public void onStop(){
super.onStop();
if (isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
unbindService(myConnection);
isBound = false;
myService.plauseAudio();
}
}
#Override
protected void onResume() {
super.onResume();
Intent objIntent = new Intent(this, MusicService.class);
if (!isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
}
public void onRestart(){
super.onRestart();
Intent objIntent = new Intent(this, MusicService.class);
if (!isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
myService.play();
}
}
}
#Override
protected void onResume() {
super.onResume();
Intent objIntent = new Intent(this, MusicService.class);
if (!isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
startService(objIntent);
}
}
public void onRestart(){
super.onRestart();
Intent objIntent = new Intent(this, MusicService.class);
if (!isBound) {
// Disconnect from an application service. You will no longer
// receive calls as the service is restarted, and the service is
// now allowed to stop at any time.
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
isBound=true;
myService.play();
}
}
}
MusicService.java
public class MusicService extends Service{
private static final String LOGCAT = null;
MediaPlayer AudioPlayer;
public void onCreate(){
super.onCreate();
Log.d(LOGCAT, "Service Started!");
AudioPlayer = MediaPlayer.create(this,R.raw.starwars_song);
}
public int onStartCommand(Intent intent, int flags, int startId){
AudioPlayer.start();
Log.d(LOGCAT, "Media Player started!");
if(AudioPlayer.isLooping() != true){
Log.d(LOGCAT, "Problem in Playing Audio");
}
return START_STICKY;
}
public void onStop(){
AudioPlayer.stop();
AudioPlayer.release();
}
public void onPause(){
AudioPlayer.stop();
AudioPlayer.release();
}
public void onDestroy(){
AudioPlayer.stop();
AudioPlayer.release();
}
public class MyLocalBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
private final IBinder myBinder = new MyLocalBinder();
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return myBinder;
}
public void plauseAudio() {
if(AudioPlayer.isPlaying())
AudioPlayer.pause();
}
public void play() {
AudioPlayer.start();
}
}
There are multiple issue on the way you implemented.
You have to start the service on activity create (if the service is already running Service.onStartCommand will be called. create MediaPlayer instance only if not null).
Bind to the service after the service started in OnCreate to establish the ServiceConnection
keep hold of the service instance till the activity is destroyed
You can pause the media in onPause if required and start again when onResume.
Unbind the service on onDestroy activity.
Stop the service if required when exit your application else service will be running. When the application is completely removed from stack, service will also be stopped. You can avoid service been killed, by running your service as Foreground using notification.
Just delete onDestroy method in your MusicService and music continues but your service become destroy.
Related
My app use a background music service.
I have a button to quit my app but I can't find anything to close my app and my service.
I bind my service to my activity.
I tried:
unbindService(serviceConnection);
myService().stopSelf();
stopService(new Intent(this, MediaPlayer.class));
and absolutely nothing works !!! The service continues.
How can I do to destroy my service and how can I do to close my app ??
Tx
EDIT:
I use this in the onCreate method
Intent intent = new Intent(this, serviceClass);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
And in the MediaPlayer class
public class LocalBinder extends Binder {
public MediaPlayer getService() {
return MediaPlayer.this;
}
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "service bound");
init();
return mBinder;
}
And that...
But I dont know if I really need to start the service. Bind the service already starts it
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Now I did this
#Override
public void onDestroy() {
player.stop();
super.onDestroy();
}
The onDestroy method works only if i unbind the service !
This doesnt work at all:
getService().stopSelf();
this.stopService(new Intent(this, MediaPlayer.class));
So, how can I stop the service and how can I close the app ?
This is what I do in my app. onDestroy() method from the activity will be called when you close your app.
private ServiceConnection musicServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
musicService.setCallbacks(MainActivity.this);
musicServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MusicService service disconnected (unbinded)");
musicServiceBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
Intent intent1 = new Intent(this, MusicService.class);
bindService(intent1, musicServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onDestroy() {
super.onDestroy()
if(musicServiceBound){
musicService.stopSelf();
unbindService(musicServiceConnection);
}
}
You wrote myService(), where you are creating another service using ().
For closing your app programmatically you can refer to this question.
I am currently working on a Pedometer application. At first, I started with one activity, the PedometerActivity. This activity started the service that is supposed to run in the background, and binds to it. The code is long so I'll just give sections of what I think will help in my question.
//Bind service
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
//binder to communicate with the service
PedometerService.PedometerBinder mBinder = (PedometerService.PedometerBinder)service;
mPedometerService = mBinder.getService();
mPedometerService.registerCallback(mCallback);
}
public void onServiceDisconnected(ComponentName className) {
mPedometerService = null;
}
};
private void startPedometerService() {
if (!isPedometerService) {
Log.v(TAG, "Start service");
isPedometerService = true;
//start service
Intent intent = new Intent(getApplicationContext(),
PedometerService.class);
startService(intent);
}
}
//Bind to the service
private void bindPedometerService() {
Log.i(TAG, "Bind service");
Intent intent = new Intent(PedometerActivity.this, PedometerService.class);
bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
}
//close connection with service
private void unbindPedometerService() {
Log.i(TAG, "Unbind service");
unbindService(mServiceConnection);
}
//Stop the service that had been started
private void stopPedometerService() {
Log.i(TAG, "Stop service");
if (mPedometerService != null) {
//stop service
Intent intent = new Intent(PedometerActivity.this, PedometerService.class);
stopService(intent);
isPedometerService = false;
}
}
#Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
startPedometerService();
bindPedometerService();
}
#Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop");
stopPedometerService();
}
public void onDestroy() {
super.onDestroy();
unbindPedometerService();
stopPedometerService();
}
In the service class that extends Service
/*Local service binding*/
public class PedometerBinder extends Binder {
public PedometerService getService() {
return PedometerService.this;
}
}
/*A client is binding to the service with bindService()
* Returns the IBinder object received in
* ServiceConnection.onServiceConnected(ComponentName,IBinder)*/
#Override
public IBinder onBind(Intent intent) {
return new PedometerBinder();
}
I then modified my application to have tablayout with 3 tabs hence 3 fragments. I pasted the code from PedometerActivity into PedometerFragment and modified it
//Bind service
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
//binder to communicate with the service
PedometerService.PedometerBinder mBinder = (PedometerService.PedometerBinder)service;
mPedometerService = mBinder.getService();
mPedometerService.registerCallback(mCallback);
}
public void onServiceDisconnected(ComponentName className) {
mPedometerService = null;
}
};
private void startPedometerService() {
if (!isPedometerService) {
Log.v(TAG, "Start service");
isPedometerService = true;
//start service
Intent intent = new Intent(getActivity().getApplicationContext(),
PedometerService.class);
getActivity().startService(intent);
}
}
//Bind to the service
private void bindPedometerService() {
Log.i(TAG, "Bind service");
Intent intent = new Intent(getActivity(), PedometerService.class);
getActivity().bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
}
//close connection with service
private void unbindPedometerService() {
Log.i(TAG, "Unbind service");
getActivity().unbindService(mServiceConnection);
}
//Stop the service that had been started
private void stopPedometerService() {
Log.i(TAG, "Stop service");
if (mPedometerService != null) {
//stop service
Intent intent = new Intent(getActivity(), PedometerService.class);
getActivity().stopService(intent);
isPedometerService = false;
}
}
#Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
startPedometerService();
bindPedometerService();
}
#Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop");
stopPedometerService();
}
public void onDestroy() {
super.onDestroy();
unbindPedometerService();
stopPedometerService();
}
The problem is am having trouble keeping the service running when I switch between tabs. I am using FragmentStatePagerAdapter and therefore when I navigate to the last tab, the first fragment (PedometerFragment) is unloaded. I have been able to save other variables in onSaveInstanceState but this does not seem to help since everything is restarted all over again.
You're using startService, so even if your bound components get destroyed, the service shouldn't be stopped. However, you're explicitly calling stopPedometerService() in onStop(), which is called when your fragment is no longer started.
Try simply removing stopPedometerService() from onStop() andonDestroy() in your fragments.
See: https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html
This version of the pager is more useful when there are a large number
of pages, working more like a list view. When pages are not visible to
the user, their entire fragment may be destroyed, only keeping the
saved state of that fragment.
You need to bind service in the Activity class. Then you can use it from any attached Fragment via interface or public methods.
I have Problem understanding the Binding to a service
I've created a simple song player, with a service to play the song.
I've created a log to track the binding and unbinding.
the problem is when i exit the app Unbinding log appears but when i go back to the app there is no binding log message ,i'm able to control play and pause of the song though
public class PlayService extends Service {
MediaPlayer mPlayer;
public IBinder mBinder=new LocalBinder();
#Override
public void onCreate() {
super.onCreate();
Log.i("TAG","Create");
mPlayer=MediaPlayer.create(this,R.raw.askme);
}
//since we want the song to be played in the background then we need to start the service
#Override
public int onStartCommand(Intent intent,int flags, int startId) {
Log.i("TAG","Start");
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
stopSelf();
}
});
return Service.START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.i("TAG","Bind");
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
Log.i("TAG","Unbind");
return super.onUnbind(intent);
}
#Override
public void onRebind(Intent intent) {
Log.i("TAG","ReBind");
super.onRebind(intent);
}
#Override
public void onDestroy() {
Log.i("TAG","Destroy");
mPlayer.release();
super.onDestroy();
}
//here are the play and pause methods frm the user
public void playSong(){
mPlayer.start();
}
public void pauseSong(){
mPlayer.pause();
}
public boolean isPlaying(){
return mPlayer.isPlaying();
}
//since Binder already Extends IBinder so
//we can create LocalBinder Class which extends IBinder Interface
public class LocalBinder extends Binder{
//this method for returning an instance of our service in the MainActivity
public PlayService getService(){
return PlayService.this;
}
}
}
and main Activity as following
public class MainActivity extends AppCompatActivity {
public static final String TAG ="TAG" ;
public PlayService mPlayService;
private Button mDownloadButton;
private Button mSongButton;
private boolean mBound=false;
private ServiceConnection mServiceConnection=new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//the iBinder object is the returned value from onBind() method in our service
mBound=true;
//we need to get an instance of our service PlayerService so we can play or Pause the song
PlayService.LocalBinder binder = (PlayService.LocalBinder) iBinder;
//and here finally we are getting an instance of our service
mPlayService= binder.getService();
if (mPlayService.isPlaying()){
mSongButton.setText("Pause");
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBound=false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDownloadButton=(Button) findViewById(R.id.download_button);
mSongButton=(Button) findViewById(R.id.song_button);
mDownloadButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"downloading",Toast.LENGTH_LONG).show();
for (String song:Playlist.songs){
Intent intent=new Intent(MainActivity.this,StartDownloadService.class);
intent.putExtra(TAG,song);
startService(intent);
}
}
});
mSongButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//here we can play or Pause the song
//but first we need to know if we are already bound to the service
if (mBound){
if (mPlayService.isPlaying()){
mPlayService.pauseSong();
mSongButton.setText("Play");
}else {
//but here we need the service to be started and keep playing in the background
//even if we unbound from the service when we exit the App
Intent intent=new Intent(MainActivity.this,PlayService.class);
startService(intent);
mPlayService.playSong();
mSongButton.setText("Pause");
}
}
}
});
}
#Override
protected void onResume() {
Intent intent=new Intent(this,PlayService.class);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
super.onResume();
}
#Override
protected void onStop() {
super.onStop();
if (mBound){
unbindService(mServiceConnection);
mBound=false;
}
}
}
if someone can explain
You are starting your service twice in your code.
Once as a started service and then as a bind service. Remove the started service code and most probably it should work as intended.
Remove this from your code
Intent intent=new Intent(MainActivity.this,PlayService.class);
startService(intent);
mPlayService.playSong();
mSongButton.setText("Pause");
as you are binding service in on Resume() method.
Intent intent=new Intent(this,PlayService.class);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
You should start and bind your music service like this:
#Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart invoked !");
// Start/Bind to play back service
Intent serviceIntent = new Intent(this, PlayService.class);
if (isMyServiceRunning(PlayService.class)
&& mBound== false) {
this.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
} else {
this.startService(serviceIntent);
this.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.i(TAG, "Media Player service is created new -------------------");
}
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop invoked !");
if(mBound) {
Log.i(TAG, "unbinding service !");
unbindService(mServiceConnection);
mBound= false;
}
}
To Check service is running or not:
/**
* Utility function to check if a service is running.
*/
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Hope this will help you !
I found the Reason
the system calls your service's onBind() method to retrieve the IBinder only when the first client binds. The system then delivers the same IBinder to any additional clients that bind, without calling onBind() again.
that's why i'm not getting the Log message from onBind() and onUnbind() method, but I've used a log message in onServiceConnected() and i got it when i ran the App again.
onDestroy() is not being called after going main->map->main->map with stopping service in this case:
After Launching the app, the MainActivity is created which starts background tracking service. On the other hand, the user can use a checkbox list in the main activity to select his interested routes where the items of the checkbox list represents the routes.
After clicking the submit button, the alarmManager starts firing the data to the IntentService class every 30 seconds. Subsequently, connection with the server is established and retrieving data to the MapActivity is started after the user was redirected automatically to the MapActivity.
The user is able to stop and start the background service by using an icon in the menu of the both activities. I am facing problem to destroy the app in the case describes below.
With the current code:
After launching the app I can stop the service in the mainActivity and destory the app.
after launching the app when I change from the main activity to the map activity , I can stop and start the service as well as destroy the app with opening Mapactivity.
When I go as the following (mainActivity->mapActivity->MainAtivity->MapActivity) and closed the app with opening map view the app is not being destroyed and the service is not stoped. Also the onDestroy() in MapActivity is not being invoked. Here the app opens with the map view again.
But when I do the following:
adding startService(i)(as the code snippet four lines below) to the onStart() in the MapActivity after bindService I can destroy the app as well stoping and starting the service but the problem here is I dont want to start the service every time I am going from the MainActivity to the MapActivity since if the user stops the service in the MainActivity it must stay off when he goes from the main to the map.
#Override
protected void onStart() {
super.onStart();
// Bind to TrackingService.
Intent intent = new Intent(this, TrackingService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
How can I destroy the app in this case in the MapActivity?
MainActivity:
public class MainActivity extends ActionBarActivity implements
AsyncTaskCallback {
boolean serviceStatus = true;
TrackingService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.route_available);
// Start the TrackingService class.
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
System.out.println("ABC MainActivity onOptionsItemSelected was invoked.");
switch (item.getItemId()) {
case R.id.menu_toggle:
if (serviceStatus) {
item.setIcon(R.drawable.off);
item.setTitle("OFF");
serviceStatus = false;
mService.stopTrackingService();
} else {
item.setIcon(R.drawable.on);
item.setTitle("ON");
serviceStatus = true;
Intent i = new Intent(this, TrackingService.class);
startService(i);
System.out.println("ABC MainActivity onOptionsitemSelected ON");
}
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onStart() {
super.onStart();
// Bind to TrackingService.
Intent intent = new Intent(this, TrackingService.class);
//To start the onPrepareOptionsMenue() after returning from the map activity to change the icon of the toggle button.
invalidateOptionsMenu();
}
#Override
protected void onStop() {
super.onStop();
//13.08.15
// Unbind from the service
if (mBound) {
unbindService(mConnection);
System.out.println("ABC MainActivity onStop() - unbindService(mConnection) was invoked. " + mBound);
mBound = false;
}else{
System.out.println("ABC MainActivity onStop() - unbindService(mConnection) was invoked. " + mBound);
}
}
#Override
protected void onDestroy() {
Intent i = new Intent(this, TrackingService.class);
stopService(i);
mService.stopTrackingService();
}
private ServiceConnection mConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
}
MapActivity
public class MapActivity extends ActionBarActivity implements OnMapReadyCallback,
ConnectionCallbacks, OnConnectionFailedListener {
boolean serviceStatus;
TrackingService mService;
boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
serviceStatus = getIntent().getExtras().getBoolean("ServiceStatusExtras");
if (serviceStatus) {
Intent i = new Intent(this, TrackingService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
startService(i);
System.out.println("ABC MapActivity onStart serviceStatus = " + serviceStatus);
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
//System.out.println("ABC Map onServiceConnected() - " + mBound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
//System.out.println("ABC Map onServiceDisconnected() - mBound");
}
};
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
markerMap.clear();
stopAlarm();
if(!serviceStatus){
Intent i = new Intent(this, TrackingService.class);
stopService(i);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_toggle:
if (serviceStatus) {
item.setIcon(R.drawable.off);
item.setTitle("OFF");
serviceStatus = false;
if(mService!=null){
mService.stopTrackingService();
}
} else {
item.setIcon(R.drawable.on);
item.setTitle("ON");
serviceStatus = true;
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
}
return super.onOptionsItemSelected(item);
}
}
TrackingService class:
public class TrackingService extends Service implements AsyncTaskCallback,
LocationListener {
LocationManager lm;
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
detectLocation();
return START_NOT_STICKY;
}
private void detectLocation() {
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 12 * 1000, 0,
this);
}
public class LocalBinder extends Binder {
TrackingService getService() {
return TrackingService.this;
}
}
public void stopTrackingService(){
if(lm != null){
lm.removeUpdates(this);
}
}
}
}
After Launching the app, the MainActivity is created which starts background tracking service. On the other hand, the user can use a checkbox list in the main activity to select his interested routes where the items of the checkbox list represents the routes.
After clicking the submit button, the alarmManager starts firing the data to the IntentService class every 30 seconds. Subsequently, connection with the server is established and retrieving data to the MapActivity is started after the user was redirected to the MapActivity.
The user is able to stop and start the background service by using an icon in the menu of the both activities. I am facing problem to destroy the app in the case describes below.
With the current code:
After launching the app I can stop the service in the mainActivity and destory the app.
after launching the app when I change from the main activity to the map activity , I can stop and start the service as well as destroy the app with opening Mapactivity.
When I go as the following (mainActivity->mapActivity->MainAtivity->MapActivity) and closed the app with opening map view the app is not being destroyed and the service is not stoped. Also the onDestroy() in MapActivity is not being invoked. Here the app opens with the map view again.
But when I do the following:
adding startService(i)(as the code snippet the four lines below) to the onStart() in the MapActivity after bindService I can destroy the app as well stoping and starting the service but the problem here is I dont want to start the service every time I am going from the MainActivity to the MapActivity since if the user stops the service in the MainActivity it must stay off when he goes from the main to the map.
#Override
protected void onStart() {
super.onStart();
// Bind to TrackingService.
Intent intent = new Intent(this, TrackingService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
How can I destroy the app in this case in the MapActivity?
MainActivity:
public class MainActivity extends ActionBarActivity implements
AsyncTaskCallback {
boolean serviceStatus = true;
TrackingService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.route_available);
// Start the TrackingService class.
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
System.out.println("ABC MainActivity onOptionsItemSelected was invoked.");
switch (item.getItemId()) {
case R.id.menu_toggle:
if (serviceStatus) {
item.setIcon(R.drawable.off);
item.setTitle("OFF");
serviceStatus = false;
mService.stopTrackingService();
} else {
item.setIcon(R.drawable.on);
item.setTitle("ON");
serviceStatus = true;
Intent i = new Intent(this, TrackingService.class);
startService(i);
System.out.println("ABC MainActivity onOptionsitemSelected ON");
}
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onStart() {
super.onStart();
// Bind to TrackingService.
Intent intent = new Intent(this, TrackingService.class);
//To start the onPrepareOptionsMenue() after returning from the map activity to change the icon of the toggle button.
invalidateOptionsMenu();
}
#Override
protected void onStop() {
super.onStop();
//13.08.15
// Unbind from the service
if (mBound) {
unbindService(mConnection);
System.out.println("ABC MainActivity onStop() - unbindService(mConnection) was invoked. " + mBound);
mBound = false;
}else{
System.out.println("ABC MainActivity onStop() - unbindService(mConnection) was invoked. " + mBound);
}
}
#Override
protected void onDestroy() {
Intent i = new Intent(this, TrackingService.class);
stopService(i);
mService.stopTrackingService();
}
private ServiceConnection mConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
}
MapActivity
public class MapActivity extends ActionBarActivity implements OnMapReadyCallback,
ConnectionCallbacks, OnConnectionFailedListener {
boolean serviceStatus;
TrackingService mService;
boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
// Bind to TrackingService.
Intent intent = new Intent(this, TrackingService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
// Intent i = new Intent(this, TrackingService.class);
// startService(i);
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
//System.out.println("ABC Map onServiceConnected() - " + mBound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
//System.out.println("ABC Map onServiceDisconnected() - mBound");
}
};
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
markerMap.clear();
stopAlarm();
Intent i = new Intent(this, TrackingService.class);
stopService(i);
mService.stopTrackingService();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_toggle:
if (serviceStatus) {
item.setIcon(R.drawable.off);
item.setTitle("OFF");
serviceStatus = false;
mService.stopTrackingService();
System.out.println("ABC Map onOptionsitemSelected OFF");
} else {
item.setIcon(R.drawable.on);
item.setTitle("ON");
serviceStatus = true;
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
}
return super.onOptionsItemSelected(item);
}
}
TrackingService class:
public class TrackingService extends Service implements AsyncTaskCallback,
LocationListener {
LocationManager lm;
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
detectLocation();
return START_NOT_STICKY;
}
private void detectLocation() {
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 12 * 1000, 0,
this);
}
public class LocalBinder extends Binder {
TrackingService getService() {
return TrackingService.this;
}
}
public void stopTrackingService(){
if(lm != null){
lm.removeUpdates(this);
}
}
}
}
Alright so from a quick look into the documentation of the Service Life Cycle:
A bound service:
The service is created when another component (a
client) calls bindService(). The client then communicates with the
service through an IBinder interface. The client can close the
connection by calling unbindService(). Multiple clients can bind to
the same service and when all of them unbind, the system destroys the
service. (The service does not need to stop itself.)
So you don't suppose to have any problem at all, the service will die when no one is bound to him.