Forked from SeanPONeil/BlockingIntentService.java
Last active
December 15, 2015 19:29
-
-
Save blork/5311410 to your computer and use it in GitHub Desktop.
Works as IntentService, based on code from AOSP. Adds intents to a LIFO stack, executes most recently added first. onHandleIntent returns boolean indicating whether the intent has already been added.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.threesquared.axawellbeing.web.services; | |
import android.app.Service; | |
import android.content.Intent; | |
import android.os.Handler; | |
import android.os.HandlerThread; | |
import android.os.IBinder; | |
import android.os.Looper; | |
import android.os.Message; | |
import java.util.Stack; | |
/** | |
* Adds intents to a LIFO stack, executes most recently added first. | |
* onHandleIntent returns boolean indicating whether the intent has already been | |
* added. | |
*/ | |
public abstract class StackIntentService extends Service { | |
/** | |
* The Class DuplicateIntentException. | |
*/ | |
@SuppressWarnings("serial") | |
public class DuplicateIntentException extends Exception { | |
} | |
private final class ServiceHandler extends Handler { | |
public ServiceHandler(Looper looper) { | |
super(looper); | |
} | |
@Override | |
public void handleMessage(Message msg) { | |
StackIntentService.this.onHandleIntent((Intent) msg.obj); | |
StackIntentService.this.stopSelf(msg.arg1); | |
} | |
} | |
protected static final String NO_ACTION = "no_action"; | |
private final String mName; | |
private boolean mRedelivery; | |
private volatile ServiceHandler mServiceHandler; | |
private volatile Looper mServiceLooper; | |
private Stack<Intent> mStack; | |
/** | |
* Creates an IntentService. Invoked by your subclass's constructor. | |
* | |
* @param name Used to name the worker thread, important only for debugging. | |
*/ | |
public StackIntentService(String name) { | |
super(); | |
this.mName = name; | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
return null; | |
} | |
@Override | |
public void onCreate() { | |
// TODO: It would be nice to have an option to hold a partial wakelock | |
// during processing, and to have a static startService(Context, Intent) | |
// method that would launch the service & hand off a wakelock. | |
super.onCreate(); | |
this.mStack = new Stack<Intent>(); | |
HandlerThread thread = new HandlerThread("IntentService[" + this.mName + "]"); | |
thread.start(); | |
this.mServiceLooper = thread.getLooper(); | |
this.mServiceHandler = new ServiceHandler(this.mServiceLooper); | |
} | |
@Override | |
public void onDestroy() { | |
this.mServiceLooper.quit(); | |
} | |
@Override | |
public void onStart(Intent intent, int startId) { | |
Message msg = this.mServiceHandler.obtainMessage(); | |
msg.arg1 = startId; | |
msg.obj = intent; | |
this.mServiceHandler.sendMessageAtFrontOfQueue(msg); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
for (Intent i : this.mStack) { | |
if (intent.filterEquals(i) | |
&& ((intent.getExtras() == null) | |
|| intent.getExtras().equals(i.getExtras()))) { | |
intent.setAction(StackIntentService.NO_ACTION); | |
break; | |
} | |
} | |
this.mStack.push(intent); | |
this.onStart(intent, startId); | |
return this.mRedelivery ? Service.START_REDELIVER_INTENT : Service.START_NOT_STICKY; | |
} | |
/** | |
* Sets intent redelivery preferences. Usually called from the constructor | |
* with your preferred semantics. | |
* <p> | |
* If enabled is true, {@link #onStartCommand(Intent, int, int)} will return | |
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before | |
* {@link #onHandleIntent(Intent)} returns, the process will be restarted | |
* and the intent redelivered. If multiple Intents have been sent, only the | |
* most recent one is guaranteed to be redelivered. | |
* <p> | |
* If enabled is false (the default), | |
* {@link #onStartCommand(Intent, int, int)} will return | |
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent | |
* dies along with it. | |
* | |
* @param enabled Set whether redelivery is enabled | |
*/ | |
public void setIntentRedelivery(boolean enabled) { | |
this.mRedelivery = enabled; | |
} | |
/** | |
* Gets the service handler. | |
* | |
* @return the service handler | |
*/ | |
protected Handler getServiceHandler() { | |
return this.mServiceHandler; | |
} | |
/** | |
* On handle intent. | |
* | |
* @param intent the intent | |
* @return true, if intent should be handled | |
*/ | |
protected boolean onHandleIntent(Intent intent) { | |
try { | |
if (!intent.getAction().equals(StackIntentService.NO_ACTION)) { | |
return true; | |
} else { | |
throw new DuplicateIntentException(); | |
} | |
} catch (DuplicateIntentException e) { | |
return false; | |
} finally { | |
this.mStack.pop(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment