OK, I understand your thinking a bit better, so hopefully I can explain a bit better.
onDestroy() is only called when your application is idle. The system will NEVER directly call a lifecycle method except when the main thread is idle If you are running some long-lived function from, say, onStart(), or a handler in the main thread. All of these are handled one at a time by the main thread's Looper. So there will be no abrupt termination of your function when onDestroy() is called. That only happens if it kills off the process. Which is a lot more likely to happen if you block the main thread -- after a while, the user will get a dialog offering to kill or wait for the busy process! Java used to support interrupting and abruptly terminating threads. However, there is absolutely NO way to make this a safe operation. Android does kill off processes, which can leave things outside the process in an inconsistent state, but that's not as bad as having your application still running, but in an inconsistent state internally! So abruptly force-quitting a method is not part of the model of any Java system. (But you can still check, and throw an exception to get out of a loop -- that will properly invoke all finally() clauses on the way out, etc.). It's hard for me to tell you the "proper" way to stop your service, because it depends on just what you're doing. You have part of the idea, by checking for a termination flag in your loop. You can set that in your onDestroy() method -- akin to what you're trying to do with your call to the undocumented Looper.quit() method. But what you want to do is to set your CARuntimes.MainServiceRunFlag instead. (Except I'd make that an instance member of your Service class, rather than a static of some other class. Better modularity, though you can make it work this way). It looks to me like what you're really trying to do, is what the system already provides for you better -- IntentService. I really don't know what their intent was, calling it this -- I think I'd call it ThreadedService, since the relevant point is that it runs your code in a separate thread. Or maybe HandlerThreadService, since it uses a handler to serialize the requests for work. You still have to be careful about things that queue up things to the current thread's looper -- like Toast, for example. Any deferred processing you want to queue up to a handler you set up in the IntentService's onCreate method (i.e. on the main thread). Anyway, the purpose of HandlerThread's and Handler's is not clean shutdown, but rather the queuing of messages via a Looper and associated MessageQueue. If you're only handling one message, ever, then creating your own thread would make sense. An AsyncTask would be a good choice if you're only running for a short time (but too long for the main thread). But if this is something that runs for an extended period of time, it would potentially block other uses of AsyncTask, so your own thread is a better choice. So anyway, to summarize -- Handler's, HandlerThread's, and IntentService give you a way to do one thing at a time in another thread. AsyncTasks give you a way to do a small number of small things in parallel (in some versions of the system, one thing at a time). Long-lived things need their own threads -- HandlerThread and IntentService can provide this. You stop a thread by testing for some condition in the loop in the thread. If the thread needs to wait, use wait(), and use notifyAll() to wake it up after you set the flag. Be sure to use the synchronized keyword to coordinate in this case! And if you loop within a handler, you're basically occupying that thread while you're looping. So be careful not to queue up any additional work to that thread's looper. (And often it needs to go to the main thread anyway -- for example, all GUI operations need to be run there). Sorry I can't make all that simple! Threading is never really simple. But there are simple patterns, and if you carefully stay within those simple patterns, you can avoid most of the complexity. Finally, about getApplicationContext() -- unfortunately, in the released versions of the documentation, there are some bad examples around this. I understand they've been fixed for the next release of the SDK. But if you're in an Activity or a Service, you just supply that activity or service, via the "this" pseudo-variable. However, in your case, your use isn't directly in the service, but in your nested ServiceHandler class, so "this" will refer to that instance instead. But you can still refer to the outer instance's this, by writing "ManagerService.this". You could also arrange to pass the context in ass a parameter when you create your ManagerService -- but since the system already does that work for you with a nested class, there's no reason. Just replace getApplicationContext() with ManagerService.this, and you're set. . On Apr 18, 11:08 am, Tejas <[email protected]> wrote: > > If you're going to do that, why involve a handler > > at all? > > Now suppose, I use any other function in my service class instead of > handler and say I'm performing a time consuming task in that function. > If the onDestroy method of the service is called, I assume that it > will terminate my function abruptly. I'm not sure of this, but I > thought so and hence used the Handler thread to have a proper > shutdown. please correct me if I'm wrong. Also let me know the right > way to stop the service. > > > Finally, never, ever, call getApplicationContext(). The return value > > is not useful to us mortals. Supply the service itself as the context. > > I'm still not sure what are you saying. How will you supply the > service as the context ? Can you provide an example ? > > On Apr 18, 2:56 am, Bob Kerns <[email protected]> wrote: > > > > > Actually, just because something is a background service does NOT mean > > it is running in a different thread. > > > Background services run in the main thread. I suspect that this point > > of confusion may be involved in your problem, though I don't quite > > spot the problem. > > > Also, you have a handler there that basically loops forever. That's > > kind of an oxymoron. If you're going to do that, why involve a handler > > at all? If I parse it correctly, it's not the main thread it'll be > > blocking, but still... if something in that thread is posting via that > > thread's looper rather than the context, that won't be processed. > > > Finally, never, ever, call getApplicationContext(). The return value > > is not useful to us mortals. Supply the service itself as the context. > > To make things maximally confusing, getApplicationContext() will > > appear to work in most circumstances. But it's always the wrong way to > > get a context to use. > > > On Apr 17, 2:05 pm, Tejas <[email protected]> wrote: > > > > Ah... I got this working. Still I'm not sure of the reason for this > > > (some thread issue I suppose) It would be great if someone can throw > > > some light on this. > > > > I was instantiating the sensor class in a background service.So the > > > thread in which it was running was different than the main thread. > > > I was doing something like this: > > > > public class ManagerService extends Service { > > > > private final String LTAG = this.getClass().getName(); > > > private volatile Looper mServiceLooper; > > > private volatile ServiceHandler mServiceHandler; > > > > private final class ServiceHandler extends Handler{ > > > public ServiceHandler(Looper myLooper) { > > > super(myLooper); > > > } > > > > public void handleMessage(Message msg) { > > > Log.v(LTAG, "handleMessage Called"); > > > super.handleMessage(msg); > > > > // Class Instantiation > > > GPSSensor gs = new GPSSensor(); > > > gs.setContext(getApplicationContext()); > > > gs.startSensing() > > > > // Main service loop > > > while(CARuntimes.MainServiceRunFlag == true){ > > > Log.v(LTAG, "In service Loop"); > > > // Do something > > > > SystemClock.sleep(60000); > > > > }//while > > > > } > > > } > > > > public void onCreate() { > > > super.onCreate(); > > > HandlerThread myThread = new HandlerThread("Main Service > > > Thread"); > > > myThread.start(); > > > > mServiceLooper = myThread.getLooper(); > > > mServiceHandler = new ServiceHandler(mServiceLooper); > > > } > > > > public void onStart(Intent intent, int startId) { > > > super.onStart(intent, startId); > > > > Message msg = mServiceHandler.obtainMessage(); > > > //msg.obj = blah blah > > > mServiceHandler.sendMessage(msg); > > > > } > > > > public void onDestroy() { > > > Log.v(LTAG, "onDestroy called, quitting looper"); > > > super.onDestroy(); > > > > mServiceLooper.quit(); > > > } > > > > public IBinder onBind(Intent arg0) { > > > return null; > > > } > > > > } > > > > So, I was instantiating the GPSSensor in the handleMessage method. I > > > moved this to the onStart method and it started working. > > > I'm not sure why it wasn't working earlier and now has started working > > > with this change. > > > It will be great if anyone can explain this. > > > > Cheers, > > > Tejas > > > > On Apr 17, 1:59 am, Tejas <[email protected]> wrote: > > > > > Hi, > > > > > My class listed below is not working. No idea whatsoever. The > > > > onLocationChanged method is never getting called ! > > > > I checked the logs for any errors/exceptions. I have the required > > > > permissions set (fine and course locations). > > > > I doubt the Context I'm setting from the caller. I'm using > > > > getApplicationContext() to pass to the setContext method in this > > > > class. > > > > Can anyone please help ? > > > > > public class GPSSensor implements CASensor { > > > > > private String LTAG = this.getClass().getName(); > > > > Context myContext; > > > > private String GPSData; > > > > public LocationManager lMgr; > > > > public LocationListener myLocListener = new LocationListener() { > > > > > public void onStatusChanged(String provider, int > > > > status, Bundle > > > > extras) { > > > > Log.v(LTAG, "=========== Here 1 ============"); > > > > } > > > > > public void onProviderEnabled(String provider) { > > > > Log.v(LTAG, "=========== Here 2 ============"); > > > > } > > > > > public void onProviderDisabled(String provider) { > > > > Log.v(LTAG, "=========== Here 3 ============"); > > > > } > > > > > public void onLocationChanged(Location location) { > > > > if (location != null){ > > > > GPSData = location.getLatitude() + "," > > > > + location.getLongitude(); > > > > Log.v(LTAG, "GPS data received > > > > ===========> " + GPSData); > > > > } > > > > else > > > > Log.v(LTAG, "Location is null > > > > ===========> "); > > > > } > > > > }; > > > > > public String getCurrentData() { > > > > return GPSData; > > > > } > > > > > public void setContext(Context context) { > > > > myContext = context; > > > > } > > > > > public boolean startSensing() { > > > > if (myContext == null){ > > > > Log.w(LTAG, "myContext not set"); > > > > return false; > > > > } > > > > Log.v(LTAG, "Starting location updates !"); > > > > > lMgr = (LocationManager) > > > > myContext.getSystemService(Context.LOCATION_SERVICE); > > > > > > > > lMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, > > > > myLocListener); > > > > > > > > //lMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, > > > > 0, myLocListener); > > > > Log.v(LTAG, "Registered myLocListener for GPS"); > > > > return true; > > > > } > > > > > public boolean stopSensing() { > > > > if (myContext == null){ > > > > Log.w(LTAG, "myContext not set"); > > > > return false; > > > > } > > > > Log.v(LTAG, "Stopping location updates !"); > > > > lMgr.removeUpdates(myLocListener); > > > > return false; > > > > } > > > > > }//GPSSensor > > > > > -- > > > > You received this message because you are subscribed to the Google > > > > Groups "Android Developers" group. > > > > To post to this group, send email to [email protected] > > > > To unsubscribe from this group, send email to > > > > [email protected] > > > > For more options, visit this group > > > > athttp://groups.google.com/group/android-developers?hl=en > > > > -- > > > You received this message because you are subscribed to the Google > > > Groups "Android Developers" group. > > > To post to this group, send email to [email protected] > > > To unsubscribe from this group, send email to > > > [email protected] > > > For more options, visit this group > > > athttp://groups.google.com/group/android-developers?hl=en > > > -- > > You received this message because you are subscribed to the Google > > Groups "Android Developers" group. > > To post to this group, send email to [email protected] > > To unsubscribe from this group, send email to > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/android-developers?hl=en

