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

Reply via email to