@@ -0,0 +1,2441 @@
+package org.ccci.gto.android.sync;%0A%0Aimport android.content.Context;%0Aimport android.content.Intent;%0Aimport android.support.annotation.NonNull;%0Aimport android.support.annotation.Nullable;%0Aimport android.support.annotation.WorkerThread;%0Aimport android.util.SparseBooleanArray;%0A%0Aimport org.ccci.gto.android.common.app.ThreadedIntentService;%0A%0Aimport java.util.concurrent.atomic.AtomicInteger;%0A%0Apublic abstract class ThreadedSyncIntentService extends ThreadedIntentService %7B%0A    static final String EXTRA_SYNCID = ThreadedSyncIntentService.class.getName() + %22.EXTRA_SYNCID%22;%0A%0A    static final SparseBooleanArray SYNCS_RUNNING = new SparseBooleanArray();%0A%0A    protected ThreadedSyncIntentService(@NonNull final String name) %7B%0A        super(name);%0A    %7D%0A%0A    protected ThreadedSyncIntentService(@NonNull final String name, final int poolSize) %7B%0A        super(name, poolSize);%0A    %7D%0A%0A    /* BEGIN lifecycle */%0A%0A    @Override%0A    protected final void onHandleIntent(@Nullable final Intent intent) %7B%0A        if (intent != null) %7B%0A            try %7B%0A                onHandleSyncIntent(intent);%0A            %7D finally %7B%0A                final int syncId = intent.getIntExtra(EXTRA_SYNCID, 0);%0A                synchronized (SYNCS_RUNNING) %7B%0A                    SYNCS_RUNNING.delete(syncId);%0A                %7D%0A                finishSync(syncId);%0A            %7D%0A        %7D%0A    %7D%0A%0A    @WorkerThread%0A    protected abstract void onHandleSyncIntent(@NonNull Intent intent);%0A%0A    /* END lifecycle */%0A%0A    protected void finishSync(final int syncId) %7B%7D%0A%0A    public static final class SyncTask implements Runnable %7B%0A        private static final int INITIAL_SYNC_ID = 1;%0A        private static final AtomicInteger NEXT_SYNC_ID = new AtomicInteger(INITIAL_SYNC_ID);%0A%0A        @NonNull%0A        private final Context mContext;%0A        @NonNull%0A        private final Intent mTask;%0A%0A        protected SyncTask(@NonNull final Context context, @NonNull final Intent task) %7B%0A            mContext = context.getApplicationContext();%0A            mTask = task;%0A        %7D%0A%0A        @Override%0A        public void run() %7B%0A            sync();%0A        %7D%0A%0A        public int sync() %7B%0A            final int syncId = NEXT_SYNC_ID.getAndIncrement();%0A            mTask.putExtra(EXTRA_SYNCID, syncId);%0A            synchronized (SYNCS_RUNNING) %7B%0A                SYNCS_RUNNING.put(syncId, true);%0A            %7D%0A            mContext.startService(mTask);%0A            return syncId;%0A        %7D%0A    %7D%0A%7D%0A

create a ThreadedSyncIntentService that handles some common sync logic