What he's doing there is specific to using a timer. I'm sure
internally, it tells the timer thread to stop processing tasks and
exit, just like I outlined earlier.

Generally speaking -- if you have a facility that provides a way to
wake it up, when trying to end a task, it's good to wake it up so it
can die. For example, setting a flag and calling notifyAll() to
unblock a thread waiting in wait(). I expect this is what calling
Timer.cancel() does, though I  haven't looked at the source.

If a Timer meets your needs, then I recommend using it; it will be
much simpler than any approach you came up yourself. However, remember
that a single timer only uses a single thread, so if it does something
that takes a long time, other scheduled tasks won't run until it
finishes. This can be a reason to use separate timers for different
tasks.

Note that this won't solve your problem above -- because calling
Timer.cancel() won't do anything to terminate YOUR loop. It terminates
the scheduling loop that waits on and runs tasks. It doesn't stop the
tasks once they're running.

On Apr 18, 8:21 pm, Tejas <tej...@gmail.com> wrote:
> Hi Bob,
>
> Thanks a lot for this. This helped me to understand a lot of things.
> I found out a good way for starting/stopping a service 
> here:http://www.brighthub.com/mobile/google-android/articles/34861.aspx
>
> What do you think of this one ?
> Cheers,
> Tejas
>
> On Apr 18, 7:03 pm, Bob Kerns <r...@acm.org> wrote:
>
>
>
> > 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 <tej...@gmail.com> 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 <r...@acm.org> 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 <tej...@gmail.com> 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) {
> > > > >  
>
> ...
>
> 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 android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to