Ok so I've built an app that uses a remote service to do some real time GPS tracking. I am using the below code to start and bind to the service.
The remote service uses aidl, sets up a notification icon, runs the GPS and locationListener. In onLocationChanged, a handler sends data back to the caller via the callback. Pretty much straight out of the examples and resources online.
I want to allow the service to continue running even if the app closes. When the app is restarted, I want the app to again bind to the service (using the existing service if running) and again receive data from the tracker.
I currently have the app mode set to singleTask and cannot use singleinstance due to another issue.
My problem is that quit often even after the app and service are shut down either from the app itself, or from AdvancedTaskKiller, or a Forceclose, the service will restart and initialize the GPS. touching on the notification will open the app. I again stop the tracking which removes the notification and turns off the GPS Close the app, and again after a few seconds the service restarts. The only way to stop it is to power off the phone.
What can I do to stop this from happening. Does it have to do with the mode of operation? START_NOT_STICKY or START_REDELIVER_INTENT? Or do I need to use stopSelf()?
My understanding is that if the service is not running when I use bindService() that the service will be created...so do I really need to use start/stopService also? I thought I would need to use it if I want the service to run even after the app is closed. That is why i do not unbind/stop the service in onDestroy(). Is this correct?
I've not seen any other info an this, so I,m not sure where to look.
Please Help! Thanks
Patrick
//Remote Service Startup
try{
startService();
}catch (Exception e) {
Toast.makeText(ctx, e.getMessage().toString(), Toast.LENGTH_SHORT).show(); }
}
try{
bindService();
}catch (Exception e) {
Toast.makeText(ctx, e.getMessage().toString(), Toast.LENGTH_SHORT).show();
}
//Remote service shutdown
try {
unbindService();
}catch(Exception e) {
Toast.makeText(ctx, e.getMessage().toString(), Toast.LENGTH_SHORT).show();
}
try{
stopService();
}catch(Exception e) {
Toast.makeText(ctx, e.getMessage().toString(), Toast.LENGTH_SHORT).show();
}
private void startService() {
if( myAdapter.trackServiceStarted() ) {
if(SETTING_DEBUG_MODE)
Toast.makeText(this, "Service already started", Toast.LENGTH_SHORT).show();
started = true;
if(!myAdapter.trackDataExists())
insertTrackData();
updateServiceStatus();
} else {
startService( new Intent ( "com.codebase.TRACKING_SERVICE" ) );
Log.d( "startService()", "startService()" );
started = true;
updateServiceStatus();
}
}
private void stopService() {
stopService( new Intent ( "com.codebase.TRACKING_SERVICE" ) );
Log.d( "stopService()", "stopService()" );
started = false;
updateServiceStatus();
}
private void bindService() {
bindService(new Intent(ITrackingService.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
bindService(new Intent(ITrackingSecondary.class.getName()),
mTrackingSecondaryConnection, Context.BIND_AUTO_CREATE);
started = true;
}
private void unbindService() {
try {
mTrackingService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
e.getMessage();
}
try {
unbindService(mTrackingSecondaryConnection);
unbindService(mConnection);
} catch (Exception e) {
// There is nothing special we need to do if the service
// has crashed.
e.getMessage();
}
started = false;
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mTrackingService = ITrackingService.Stub.asInterface(service);
// We want to monitor the service for as long as we are
// connected to it.
try {
mTrackingService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mTrackingService = null;
}
};
private ServiceConnection mTrackingSecondaryConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// Connecting to a secondary interface is the same as any
// other interface.
mTrackingSecondaryService = ITrackingSecondary.Stub.asInterface(service);
try{
mTrackingSecondaryService.setTimePrecision(SETTING_TIME_PRECISION);
mTrackingSecondaryService.setDistancePrecision(SETTING_DISTANCE_PRECISION);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
mTrackingSecondaryService = null;
}
};
//TrackService onDestry()
public void onDestroy() {
try{
if(lm != null) {
lm.removeUpdates(this);
}
if(mNotificationManager != null) {
mNotificationManager.cancel(R.string.local_service_started);
}
Toast.makeText(this, "Service stopped", Toast.LENGTH_SHORT).show();
}catch (Exception e){
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
// Unregister all callbacks.
mCallbacks.kill();
// Remove the next pending message to increment the counter, stopping
// the increment loop.
mHandler.removeMessages(REPORT_MSG);
super.onDestroy();
}
ServiceConnectionLeaked: I'm seeing a lot of these:
04-21 09:25:23.347: ERROR/ActivityThread(3246): Activity com.codebase.GPSTest has leaked ServiceConnection com.codebase.GPSTest$6@4482d428 that was originally bound here
04-21 09:25:23.347: ERROR/ActivityThread(3246): android.app.ServiceConnectionLeaked: Activity com.codebase.GPSTest has leaked ServiceConnection com.codebase.GPSTest$6@4482d428 that was originally bound here
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:977)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:872)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ApplicationContext.bindService(ApplicationContext.java:796)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.content.ContextWrapper.bindService(ContextWrapper.java:337)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at com.codebase.GPSTest.bindService(GPSTest.java:2206)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at com.codebase.GPSTest.onStartStopClick(GPSTest.java:1589)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at com.codebase.GPSTest.onResume(GPSTest.java:1210)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1149)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.Activity.performResume(Activity.java:3763)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2937)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2965)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2516)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3625)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.access$2300(ActivityThread.java:119)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1867)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.os.Handler.dispatchMessage(Handler.java:99)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.os.Looper.loop(Looper.java:123)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at android.app.ActivityThread.main(ActivityThread.java:4363)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at java.lang.reflect.Method.invokeNative(Native Method)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at java.lang.reflect.Method.invoke(Method.java:521)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
04-21 09:25:23.347: ERROR/ActivityThread(3246): at dalvik.system.NativeStart.main(Native Method)
And These: Is this ok, or do I need to make sure i deactivate/close
04-21 09:58:55.487: INFO/dalvikvm(3440): Uncaught exception thrown by finalizer (will be discarded):
04-21 09:58:55.487: INFO/dalvikvm(3440): Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor@447ef258 on gps_data that has not been deactivated or closed
04-21 09:58:55.487: INFO/dalvikvm(3440): at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596)
04-21 09:58:55.487: INFO/dalvikvm(3440): at dalvik.system.NativeStart.run(Native Method)