Services
satya - Thursday, June 03, 2010 10:13:53 AM
Read up on this IntentService
satya - Thursday, June 03, 2010 10:16:03 AM
Here is an explanation from the api
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.
satya - Thursday, June 03, 2010 10:21:45 AM
IntentService
IntentService
Search Google for: IntentService
Search Android Developers Group for: IntentService
Search Android Beginers Group for: IntentService
satya - Thursday, June 03, 2010 10:25:18 AM
IntentService doesn't holde a wakelock
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.
satya - Thursday, June 03, 2010 10:28:32 AM
IntentService wakelock
IntentService wakelock
Search Google for: IntentService wakelock
Search Android Developers Group for: IntentService wakelock
Search Android Beginers Group for: IntentService wakelock
satya - Thursday, June 03, 2010 12:49:34 PM
Here is a link to the source code of IntentService.java
satya - Thursday, June 03, 2010 12:53:03 PM
Here is the source code
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);
}
satya - Thursday, June 03, 2010 2:24:11 PM
Understand stopSelf(int) method
satya - Thursday, June 03, 2010 4:00:25 PM
Here is an implementation of IntentService using a wakelock from Commonguy
Here is an implementation of IntentService using a wakelock from Commonguy
satya - Thursday, June 03, 2010 4:07:29 PM
Can I acquire wakelock in the onCreate() of a service?
Can I acquire wakelock in the onCreate() of a service?
Search for: Can I acquire wakelock in the onCreate() of a service?
satya - Thursday, June 03, 2010 10:49:04 PM
wakelock service
wakelock service
Search Google for: wakelock service
Search Android Developers Group for: wakelock service
Search Android Beginers Group for: wakelock service
satya - Friday, June 04, 2010 8:49:19 AM
More on alarm managers, wake locks, and services
satya - Friday, June 04, 2010 8:54:09 AM
Crux of that thread
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.
satya - Friday, June 04, 2010 9:02:05 AM
More cruxes...
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.
satya - Friday, June 04, 2010 9:27:18 AM
More Predicates...
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.
satya - Friday, June 04, 2010 10:24:07 AM
wakelock release service dies
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
satya - Friday, June 04, 2010 10:28:54 AM
Another summary from above
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.
satya - Friday, June 04, 2010 5:07:47 PM
See this for interaction between wakelock and services
satya - Saturday, June 05, 2010 9:06:20 AM
PowerManager.java
PowerManager.java
satya - Saturday, June 05, 2010 9:08:10 AM
Here is the source code link for PowerManager.java
satya - Saturday, June 05, 2010 9:12:39 AM
PowerManager.wakelock source code
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));
}
}
}
}
satya - Saturday, June 05, 2010 9:30:27 AM
Will stopping an android service call or trigger ondestroy
Will stopping an android service call or trigger ondestroy
Search for: Will stopping an android service call or trigger ondestroy
satya - Saturday, June 05, 2010 9:31:15 AM
stop service 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
satya - Saturday, June 05, 2010 9:39:43 AM
It probably triggers it. See this thread
satya - Saturday, June 05, 2010 9:40:22 AM
stopself ondestroy
stopself ondestroy
Search Google for: stopself ondestroy
Search Android Developers Group for: stopself ondestroy
Search Android Beginers Group for: stopself ondestroy
satya - Saturday, June 05, 2010 9:14:21 PM
Sample wakelock permission
<uses-permission android:name="android.permission.WAKE_LOCK" />
satya - Saturday, June 05, 2010 9:16:37 PM
Some sample available permissions
<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" />
satya - Wednesday, June 09, 2010 10:45:25 PM
Services are fundamentally sticky
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.
satya - Wednesday, June 09, 2010 10:55:03 PM
what is a non sticky service then?
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".
satya - Wednesday, June 09, 2010 10:58:50 PM
How ever non-sticky is not really not non-sticky...
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.
satya - Wednesday, June 09, 2010 11:07:06 PM
What it means to be really "sticky" then?
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.
satya - Wednesday, June 09, 2010 11:17:40 PM
A variation of non-sticky: Redeliver intents
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.
satya - Wednesday, June 09, 2010 11:24:39 PM
Interestingly the stickyness is tied to "onstartcommand" and not to service
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
satya - Wednesday, June 09, 2010 11:32:35 PM
The OnStartCommand
For backwards compatibility, the default implementation calls onStart(Intent, int) and returns either START_STICKY or START_STICKY_COMPATIBILITY.
satya - Wednesday, June 09, 2010 11:34:25 PM
backward 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;
}
satya - Wednesday, June 09, 2010 11:37:24 PM
what are the implications for a long running broadcast receiver
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
satya - Wednesday, June 09, 2010 11:40:31 PM
what type of service is suitable for a long running broadcast receiver...
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.