package com.mcxiaoke.next.app; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.SystemClock; import com.mcxiaoke.next.utils.LogUtils; import com.mcxiaoke.next.utils.ThreadUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; /** * 类似于IntentService,但是多个异步任务可以并行执行 * Service每隔300秒自动检查,如果活跃任务目为0则自动结束 * 自动结束时间可设置,是否启用自动结束功能可设置 * User: mcxiaoke * Date: 14-4-22 14-05-22 * Time: 14:04 */ public abstract class MultiIntentService extends Service { // 默认空闲5分钟后自动stopSelf() public static final long AUTO_CLOSE_DEFAULT_TIME = 300 * 1000L; private static final String BASE_TAG = MultiIntentService.class.getSimpleName(); private static final String SEPARATOR = "::"; private static volatile long sSequence = 0L; private final Object mLock = new Object(); private final Runnable mAutoCloseRunnable = new Runnable() { @Override public void run() { autoClose(); } }; private ExecutorService mExecutor; private Handler mHandler; private volatile Map<String, Future<?>> mFutures; private volatile AtomicInteger mRetainCount; private boolean mAutoCloseEnable; private long mAutoCloseTime; public MultiIntentService() { super(); } static long incSequence() { return ++sSequence; } @Override public void onCreate() { super.onCreate(); LogUtils.v(BASE_TAG, "onCreate()"); mRetainCount = new AtomicInteger(0); mFutures = new ConcurrentHashMap<String, Future<?>>(); mAutoCloseEnable = true; mAutoCloseTime = AUTO_CLOSE_DEFAULT_TIME; ensureHandler(); ensureExecutor(); checkAutoClose(); } @Override public final int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { dispatchIntent(intent); } return START_NOT_STICKY; } @Override public void onDestroy() { super.onDestroy(); LogUtils.v(BASE_TAG, "onDestroy() mRetainCount=" + mRetainCount.get()); LogUtils.v(BASE_TAG, "onDestroy() mFutures.size()=" + mFutures.size()); cancelAutoClose(); destroyHandler(); destroyExecutor(); } @Override public IBinder onBind(Intent intent) { return null; } protected void setAutoCloseEnable(boolean enable) { mAutoCloseEnable = enable; checkAutoClose(); } protected void setAutoCloseTime(long milliseconds) { mAutoCloseTime = milliseconds; checkAutoClose(); } protected boolean isIdle() { return mRetainCount.get() <= 0; } protected final void cancel(final String tag) { Future<?> future; synchronized (mLock) { future = mFutures.get(tag); } if (future != null) { future.cancel(true); release(tag); } } private void dispatchIntent(final Intent intent) { final String tag = buildTag(intent); final Runnable runnable = new Runnable() { @Override public void run() { LogUtils.v(BASE_TAG, "dispatchIntent thread=" + Thread.currentThread()); LogUtils.v(BASE_TAG, "dispatchIntent start tag=" + tag); onHandleIntent(intent, tag); LogUtils.v(BASE_TAG, "dispatchIntent end tag=" + tag); release(tag); } }; Future<?> future = submit(runnable); retain(tag, future); } protected void retain(final String tag, final Future<?> future) { LogUtils.v(BASE_TAG, "retain() tag=" + tag); mRetainCount.incrementAndGet(); mFutures.put(tag, future); } protected void release(final String tag) { LogUtils.v(BASE_TAG, "release() tag=" + tag); mRetainCount.decrementAndGet(); synchronized (mLock) { mFutures.remove(tag); } checkAutoClose(); } private void checkAutoClose() { if (mAutoCloseEnable) { scheduleAutoClose(); } else { cancelAutoClose(); } } private void scheduleAutoClose() { if (mAutoCloseTime > 0) { LogUtils.v(BASE_TAG, "scheduleAutoClose()"); if (mHandler != null) { mHandler.postDelayed(mAutoCloseRunnable, mAutoCloseTime); } } } private void cancelAutoClose() { LogUtils.v(BASE_TAG, "cancelAutoClose()"); if (mHandler != null) { mHandler.removeCallbacks(mAutoCloseRunnable); } } private void autoClose() { LogUtils.v(BASE_TAG, "autoClose() mRetainCount=" + mRetainCount.get()); LogUtils.v(BASE_TAG, "autoClose() mFutures.size()=" + mFutures.size()); if (isIdle()) { stopSelf(); } } private void ensureHandler() { if (mHandler == null) { mHandler = new Handler(); } } private void destroyHandler() { synchronized (mLock) { if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); mHandler = null; } } } private ExecutorService ensureExecutor() { if (mExecutor == null || mExecutor.isShutdown()) { mExecutor = createExecutor(); } return mExecutor; } private void destroyExecutor() { if (mExecutor != null) { mExecutor.shutdownNow(); mExecutor = null; } } private String buildTag(final Intent intent) { final long hashCode = System.identityHashCode(intent); final long sequence = incSequence(); final long timestamp = SystemClock.elapsedRealtime(); StringBuilder builder = new StringBuilder(); builder.append(hashCode).append(SEPARATOR); builder.append(timestamp).append(SEPARATOR); builder.append(sequence); return builder.toString(); } private Future<?> submit(Runnable runnable) { ensureExecutor(); return mExecutor.submit(runnable); } protected ExecutorService createExecutor() { return ThreadUtils.newCachedThreadPool(BASE_TAG); } /** * 此方法在非UI线程执行 * * @param intent Intent * @param tag TAG,可以用于取消任务 */ protected abstract void onHandleIntent(final Intent intent, final String tag); }