Coclusion: onDestroy() is not always being invoked.
Here is the 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:
onDestroy()
in MapActivity is not being invoked. Here the app opens gain with the map view. 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);
}
I know that there's no guarantee of when onDestroy() will be called in an Activity and maybe I should call finish()
inside onPause() or onStop() but my question is how to know when to call finish() inside onPause() or onStop() since the tracking service should run in the background until the app is being destroyed by the user or the user decides to stop it with the icon in the menu. I dont want to stop the tracking service when the user goes in the background or everytime onPause()
is being called (In my case onPause() in the MapActivity is being called several time in one minute).
How can I call finish()
from onPause()
or onStop()
only when the user destroys the app? How to manage it in this case?
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);
}
}
}
}
a classic solution is to have a static counter that is increased at each activity "onStart" and decreased on "onPause".
when counter is at 0, app is really closed
the only hard part is if you have orientation change on your first activity, as activity is completely destroyed and recreated by system, you may think that app is really closed (as counter is at 0 in this situation)
i have no magic solution for this particular case
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.