Services

base read: api

Read up on this IntentService

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

IntentService

Search Google for: IntentService

Search Android Developers Group for: IntentService

Search Android Beginers Group for: IntentService

Search Google Code for: IntentService

Search Android Issues Database for: IntentService

IntentService doesn't holde a wakelock

Summary from Dianne (as of May 2009): It doesn't hold a wake lock... and unfortunately to correctly use a wake lock with the alarm manager, you need to have the alarm delivered to a broadcast receiver. This is something that we'd really like to improve.

IntentService wakelock

Search Google for: IntentService wakelock

Search Android Developers Group for: IntentService wakelock

Search Android Beginers Group for: IntentService wakelock

Search Google Code for: IntentService wakelock

Search Android Issues Database for: IntentService wakelock

Here is a link to the source code of IntentService.java


package android.app;

import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;

/**
 * An abstract {@link Service} that serializes the 
 * handling of the Intents passed upon service
 * start and handles them on a handler thread.
 *
 * To use this class extend it and implement {@link #onHandleIntent}. 
 * The {@link Service} will automatically be stopped 
 * when the last enqueued {@link Intent} is handled.
 */
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = 
          new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * Invoked on the Handler thread with the {@link Intent} 
    * that is passed to {@link #onStart}.
     * Note that this will be invoked from a 
    * different thread than the one that handles the
     * {@link #onStart} call.
     */
    protected abstract void onHandleIntent(Intent intent);
}

Understand stopSelf(int) method

Here is an implementation of IntentService using a wakelock from Commonguy

Can I acquire wakelock in the onCreate() of a service?

Search for: Can I acquire wakelock in the onCreate() of a service?

wakelock service

Search Google for: wakelock service

Search Android Developers Group for: wakelock service

Search Android Beginers Group for: wakelock service

Search Google Code for: wakelock service

Search Android Issues Database for: wakelock service

More on alarm managers, wake locks, and services

Quoting from Dianne...

Please read again my explanation about what you need to do to keep the device from going to sleep -- you need to have the alarm sent to a broadcast receiver, which immediately acquires a partial wake lock, which then starts the service, and the partial wake lock is not released until the service completes its work.

Your code has two holes in wake locks: (1) the broadcast can complete before the service is started, (2) you aren't taking the wake lock until your thread is running, so even if (1) was not a problem you could still end up with the system releasing its wake lock before your thread is running.

Also, please look at the API demos for alarms and services. You want to deliver Intent to the service's onStart(), and use that to schedule work in the service.

Again further quoting Dianne...

First, don't use registerReceiver(). Having a service always running is a -huge- waste of resources. In fact this will probably be counter-productive, because as the system gets low on resource and starts struggling to see what it can free up, it will see your service having sitting there run for a long long time and start considering it a tempting candidate for the kill. (If nothing else, because long running processes often have leaks or just memory fragmentation in them, so killing them and letting them restart at some point in the future can free up memory even after they are running again.)

Yes you need to use a global variable for the wake lock. Gross, but it works.

Please look at the ApiDemo for Service Start Arguments. This shows how a service can have work coming from multiple client via startService() and correctly manage its lifecycle to stop itself when it is done and there is no more incoming work. (The key is stopSelf(int id).) So your intent receiver can start the service, and your app can also do so.

wakelock must be obtained in the mainline of the broadcast receiver code. Otherwise the device can go to sleep if you do this in the onCreate() of the service.

Only way the service can interact with the wakelock created by the BCR (Broadcast Receiver) is through a static variable. Because the service that starts from the manifest file doesnt have a constructor that takes arguments and you can't pass reference to the wake lock.

wakelock release service dies

Search Google for: wakelock release service dies

Search Android Developers Group for: wakelock release service dies

Search Android Beginers Group for: wakelock release service dies

Search Google Code for: wakelock release service dies

Search Android Issues Database for: wakelock release service dies

Another good read on threads

Basically you should have things you want to continue running in the background implemented as a Service.

Also there is generally no need to create a whole new Thread for this kind of stuff, you can just post delayed messages to your own handler.

Finally, for something like a countdown timer, you really might want to consider using the alarm manager so you don't need to keep your app running at all while it is in the background. That is the kind of thing a well behaving Android app will do. To be able to show the remaining time if the user returns to your activity, you can store on SharedPreferences the time the countdown was started.

Using the alarm manager is also the only way you can make sure you execute when the time expires, even if the user has turned off the phone.

See this for interaction between wakelock and services

PowerManager.java

Search for: PowerManager.java

Here is the source code link for PowerManager.java


public class WakeLock
{
   static final int RELEASE_WAKE_LOCK = 1;

   Runnable mReleaser = new Runnable() {
      public void run() {
         release();
      }
   };

   int mFlags;
   String mTag;
   IBinder mToken;
   int mCount = 0;
   boolean mRefCounted = true;
   boolean mHeld = false;

   WakeLock(int flags, String tag)
   {
      switch (flags & LOCK_MASK) {
      case PARTIAL_WAKE_LOCK:
      case SCREEN_DIM_WAKE_LOCK:
      case SCREEN_BRIGHT_WAKE_LOCK:
      case FULL_WAKE_LOCK:
         break;
      default:
         throw new IllegalArgumentException();
      }

      mFlags = flags;
      mTag = tag;
      mToken = new Binder();
   }

   /**
    * Sets whether this WakeLock is ref counted.
    *
    * @param value true for ref counted, false for not ref counted.
    */
   public void setReferenceCounted(boolean value)
   {
      mRefCounted = value;
   }

   /**
    * Makes sure the device is on at the level you asked when you created
    * the wake lock.
    */
   public void acquire()
   {
      synchronized (mToken) {
         if (!mRefCounted || mCount++ == 0) {
            try {
               mService.acquireWakeLock(mFlags, mToken, mTag);
            } catch (RemoteException e) {
            }
            mHeld = true;
         }
      }
   }
   
   /**
    * Makes sure the device is on at the level you asked when you created
    * the wake lock. The lock will be released after the given timeout.
    * 
    * @param timeout Release the lock after the give timeout in milliseconds.
    */
   public void acquire(long timeout) {
      acquire();
      mHandler.postDelayed(mReleaser, timeout);
   }
   

   /**
    * Release your claim to the CPU or screen being on.
    *
    * <p>
    * It may turn off shortly after you release it, or it may not if there
    * are other wake locks held.
    */
   public void release()
   {
      synchronized (mToken) {
         if (!mRefCounted || --mCount == 0) {
            try {
               mService.releaseWakeLock(mToken);
            } catch (RemoteException e) {
            }
            mHeld = false;
         }
         if (mCount < 0) {
            throw new RuntimeException("WakeLock under-locked " + mTag);
         }
      }
   }

   public boolean isHeld()
   {
      synchronized (mToken) {
         return mHeld;
      }
   }

   public String toString() {
      synchronized (mToken) {
         return "WakeLock{"
            + Integer.toHexString(System.identityHashCode(this))
            + " held=" + mHeld + ", refCount=" + mCount + "}";
      }
   }

   @Override
   protected void finalize() throws Throwable
   {
      synchronized (mToken) {
         if (mHeld) {
            try {
               mService.releaseWakeLock(mToken);
            } catch (RemoteException e) {
            }
            RuntimeInit.crash(TAG, new Exception(
                     "WakeLock finalized while still held: "+mTag));
         }
      }
   }
}

Will stopping an android service call or trigger ondestroy

Search for: Will stopping an android service call or trigger ondestroy

stop service ondestroy

Search Google for: stop service ondestroy

Search Android Developers Group for: stop service ondestroy

Search Android Beginers Group for: stop service ondestroy

Search Google Code for: stop service ondestroy

Search Android Issues Database for: stop service ondestroy

It probably triggers it. See this thread

stopself ondestroy

Search Google for: stopself ondestroy

Search Android Developers Group for: stopself ondestroy

Search Android Beginers Group for: stopself ondestroy

Search Google Code for: stopself ondestroy

Search Android Issues Database for: stopself ondestroy


<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- We will request access to the camera, saying we require a camera
	 of some sort but not one with autofocus capability. -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" 
      android:required="false" />

Unlike other components Android restarts a service component. Android has made enough provisions to make a service running. However under demanding memory conditions Android may choose to reclaim the process and call "ondestory". Android tries to do this when the service is not executing its "oncreate", "onstart" or "ondestroy" methods.

However unlike an activity that is shutdown, a service is scheduled to restart again when resources are available.

This is especially true if there are pending "startService" intents. The service will be woken up and the next intent delivered to it via "onstartcommand".

Ofcourse the "oncreate" will be called when the service is brought back again.

Because services are restarted all the time it is reasonable to think that unlike activity and other components, a service component is fundamentally a sticky component.

Let us see when a service is not restarted. After some client calls "startservice" the service is created and its "onstartcommand" called to do its work. This service will not be automatically restarted if a client explicitly calls "stopservice". This "stopservice" depending on how many clients there are can move the service into a stopped state. At which time the services ondestroy is called and the service life cycle is complete and will not brought back.

Starting in Android 2.0 android provides another feature where by you can indicate that a service can stay dead and a resurrection is not needed. This is the case when the service is taken out due to memory constraints and the its "stopself" or "stopservice" is not called. As a result the service when recreated will stay there and never go out because it is never stopped and keeps getting recreated. One solution android 2.0 offers is to indicate to android that if there are no pending intents don't bother restarting it. This is ok because who ever started the service to do the work will call it again such as the alarm manager. This is done by returning the "non sticky" flag from the "onstartcommand".

Remember even if we mark the service as non-sticky, if there are pending intents android will bring it back to life. So this setting applies only when there are no more pending intents.

Sticky means, restart the service even if there are no pending intents.

When it is restarted, call "oncreate" and also call the "onstartcommand" with a null intent. This will give an opportunity, if need be, to the service that to call the "stopself" if that is appropriate.

The implication is that a service that is sticky need to deal with "null" intent on restarts.

Especially local services follow a pattern where "onstart" and "stopself" are called in pairs. A client calls the "onstart" and the Service when finishes that work calls the "stopself".

If a service takes say 30 minutes to complete a task, it will not call "stopself" for 30 minutes. Meanwhile the service is reclaimed. If we say non-sticky then the service will not wake up and we would never have called "stopself". Many times this is ok. However if you want to make sure if these two calls are happen for sure, you can tell android to not to "unque" the "start" event until the "stopself" is called.

This ensures that when the service is reclaimed there is always a pending event unless the stopself is called. This is called the "redeliver" mode which can be indicated in reply to "onstartcommand" method.

So far I have been talking about a service being sticky and not sticky or redeliver as if these are service level attributes.

However this determination is made based on the return value from the "onstartcommand".

I wonder what the goal here is. Because for the same service instance the "onstartcommand" is called many times once for each "startservice". what if it returns different flags indicating different service behaviors.

I can assume that the last returned value is what determines. However it seems odd on that count

For backwards compatibility, the default implementation calls onStart(Intent, int) and returns either START_STICKY or START_STICKY_COMPATIBILITY.


// This is the old onStart method that will be called on the pre-2.0
// platform.  On 2.0 or later we override onStartCommand() so this
// method will not be called.
@Overridepublic void onStart(Intent intent, int startId) 
{    
   handleCommand(intent);
}
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) 
{    
   handleCommand(intent);    
   // We want this service to continue running until it is explicitly    
   // stopped, so return sticky.    
   return START_STICKY;
}

There are two ways that service can come to life. a) The broadcast receiver starts it off. b) Service wakes up at a later time.

If you intend to acquire a wakelock you will have to do this in both places. Moreover you have to acquire the lock at the earliest.

you can turn the lock off in possibly two places. a) After doing the stopself b) In destroy

From what I see a simple "nonsticky" will do. I am finding hard to think that there is a usecase for "sticky" long running broadcast receivers, especially if we want to use the "IntentService" which expects the service to stop if there are no pending intents.

There may be a case of "redeliver" type of non-sticky, but even that I am not seeing a usecase.

So as long as it is a simple non sticky and we turn off the lock in destory and also after stopself we are good.