1 /**
2 * IntentService is a base class for {@link Service}s that handle asynchronous
3 * requests (expressed as {@link Intent}s) on demand. Clients send requests
4 * through {@link android.content.Context#startService(Intent)} calls; the
5 * service is started as needed, handles each Intent in turn using a worker
6 * thread, and stops itself when it runs out of work.
7 *
8 * <p>This "work queue processor" pattern is commonly used to offload tasks
9 * from an application's main thread. The IntentService class exists to
10 * simplify this pattern and take care of the mechanics. To use it, extend
11 * IntentService and implement {@link #onHandleIntent(Intent)}. IntentService
12 * will receive the Intents, launch a worker thread, and stop the service as
13 * appropriate.
14 *
15 * <p>All requests are handled on a single worker thread -- they may take as
16 * long as necessary (and will not block the application's main loop), but
17 * only one request will be processed at a time.
18 *
19 * <div class="special reference">
20 * <h3>Developer Guides</h3>
21 * <p>For a detailed discussion about how to create services, read the
22 * <a href="{@docRoot}guide/components/services.html">Services</a> developer
23 * guide.</p>
24 * </div>
25 *
26 * @see android.os.AsyncTask
27 */
28 public abstract class IntentService extends Service {
29 private volatile Looper mServiceLooper;
30 private volatile ServiceHandler mServiceHandler;
31 private String mName;
32 private boolean mRedelivery;
33
34 private final class ServiceHandler extends Handler {
35 public ServiceHandler(Looper looper) {
36 super(looper);
37 }
38
39 @Override
40 public void handleMessage(Message msg) {
41 onHandleIntent((Intent)msg.obj);
42 stopSelf(msg.arg1);
43 }
44 }
45
46 /**
47 * Creates an IntentService. Invoked by your subclass's constructor.
48 *
49 * @param name Used to name the worker thread, important only for debugging.
50 */
51 public IntentService(String name) {
52 super();
53 mName = name;
54 }
55
56 /**
57 * Sets intent redelivery preferences. Usually called from the constructor
58 * with your preferred semantics.
59 *
60 * <p>If enabled is true,
61 * {@link #onStartCommand(Intent, int, int)} will return
62 * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
63 * {@link #onHandleIntent(Intent)} returns, the process will be restarted
64 * and the intent redelivered. If multiple Intents have been sent, only
65 * the most recent one is guaranteed to be redelivered.
66 *
67 * <p>If enabled is false (the default),
68 * {@link #onStartCommand(Intent, int, int)} will return
69 * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
70 * dies along with it.
71 */
72 public void setIntentRedelivery(boolean enabled) {
73 mRedelivery = enabled;
74 }
75
76 @Override
77 public void onCreate() {
78 // TODO: It would be nice to have an option to hold a partial wakelock
79 // during processing, and to have a static startService(Context, Intent)
80 // method that would launch the service & hand off a wakelock.
81
82 super.onCreate();
83 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
84 thread.start();
85
86 mServiceLooper = thread.getLooper();
87 mServiceHandler = new ServiceHandler(mServiceLooper);
88 }
89
90 @Override
91 public void onStart(@Nullable Intent intent, int startId) {
92 Message msg = mServiceHandler.obtainMessage();
93 msg.arg1 = startId;
94 msg.obj = intent;
95 mServiceHandler.sendMessage(msg);
96 }
97
98 /**
99 * You should not override this method for your IntentService. Instead,
100 * override {@link #onHandleIntent}, which the system calls when the IntentService
101 * receives a start request.
102 * @see android.app.Service#onStartCommand
103 */
104 @Override
105 public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
106 onStart(intent, startId);
107 return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
108 }
109
110 @Override
111 public void onDestroy() {
112 mServiceLooper.quit();
113 }
114
115 /**
116 * Unless you provide binding for your service, you don't need to implement this
117 * method, because the default implementation returns null.
118 * @see android.app.Service#onBind
119 */
120 @Override
121 @Nullable
122 public IBinder onBind(Intent intent) {
123 return null;
124 }
125
126 /**
127 * This method is invoked on the worker thread with a request to process.
128 * Only one Intent is processed at a time, but the processing happens on a
129 * worker thread that runs independently from other application logic.
130 * So, if this code takes a long time, it will hold up other requests to
131 * the same IntentService, but it will not hold up anything else.
132 * When all requests have been handled, the IntentService stops itself,
133 * so you should not call {@link #stopSelf}.
134 *
135 * @param intent The value passed to {@link
136 * android.content.Context#startService(Intent)}.
137 * This may be null if the service is being restarted after
138 * its process has gone away; see
139 * {@link android.app.Service#onStartCommand}
140 * for details.
141 */
142 @WorkerThread
143 protected abstract void onHandleIntent(@Nullable Intent intent);
144 }