<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/task/TaskGraph.java<|end_filename|>
package com.ryan.github.launcher.task;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Vector;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class TaskGraph {

    //顶点数
    private int mVertexCount;
    //邻接表
    private List<Integer>[] mVertexArr;

    @SuppressWarnings("unchecked")
    public TaskGraph(int vertexCount) {
        mVertexCount = vertexCount;
        mVertexArr = new ArrayList[vertexCount];
        for (int i = 0; i < vertexCount; i++) {
            mVertexArr[i] = new ArrayList<>();
        }
    }

    /**
     * 添加边
     *
     * @param u from
     * @param v to
     */
    public void addEdge(int u, int v) {
        mVertexArr[u].add(v);
    }

    /**
     * 拓扑排序
     */
    public Vector<Integer> topologicalSort() {
        int inDegrees[] = new int[mVertexCount];
        for (int i = 0; i < mVertexCount; i++) { // 初始化所有点的入度数量
            ArrayList<Integer> temp = (ArrayList<Integer>) mVertexArr[i];
            for (int node : temp) {
                inDegrees[node]++;
            }
        }
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < mVertexCount; i++) { // 找出所有入度为0的点
            if (inDegrees[i] == 0) {
                queue.add(i);
            }
        }
        int cnt = 0;
        Vector<Integer> topOrder = new Vector<>();
        while (!queue.isEmpty()) {
            int u = queue.poll();
            topOrder.add(u);
            for (int node : mVertexArr[u]) { // 找到该点（入度为0）的所有邻接点
                if (--inDegrees[node] == 0) { // 把这个点的入度减一，如果入度变成了0，那么添加到入度0的队列里
                    queue.add(node);
                }
            }
            cnt++;
        }
        if (cnt != mVertexCount) { // 检查是否有环，理论上拿出来的点的次数和点的数量应该一致，如果不一致，说明有环
            throw new IllegalStateException("Exists a cycle in the graph");
        }
        return topOrder;
    }

}

<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/executor/MainExecutor.java<|end_filename|>
package com.ryan.github.launcher.executor;

import android.os.Handler;
import android.os.Looper;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class MainExecutor implements TaskExecutor {

    private static final Handler mMainHandler = new Handler(Looper.getMainLooper());

    public static MainExecutor getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final MainExecutor INSTANCE = new MainExecutor();
    }

    private MainExecutor() {
    }

    @Override
    public void execute(Runnable runnable) {
        mMainHandler.post(runnable);
    }

    @Override
    public void shutdown() {

    }
}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/MainApplication.java<|end_filename|>
package com.ryan.github.launcher.sample;

import android.app.Application;
import android.util.Log;

import com.ryan.github.launcher.AppLauncher;
import com.ryan.github.launcher.listener.IdleHandler;

import static com.ryan.github.launcher.sample.Constants.TAG;

/**
 * created by 2019/7/2 12:30 AM
 *
 * @author Ryan
 */
public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        AppLauncher launcher = new AppLauncher.Builder()
                .addTask(new SimpleLauncherTask7())
                .addTask(new SimpleLauncherTask2())
                .addTask(new SimpleLauncherTask3())
                .addTask(new SimpleLauncherTask1())
                .addTask(new SimpleLauncherTask4())
                .addTask(new SimpleLauncherTask6())
                .addTask(new SimpleLauncherTask5())
                .addHeadTask(new SimpleLauncherTask8())
                .addTailTask(new SimpleLauncherTask9())
                .addHeadTask(new SimpleLauncherTask10())
                .addHeadTask(new SimpleLauncherTask11())
                .addTailTask(new SimpleLauncherTask12())
                .addDelayTask(new SimpleLauncherTask13())
                .idleHandler(new IdleHandler() {
                    @Override
                    public void onIdle() {
                        Log.v(TAG, "onIdle");
                    }
                }).start();
        launcher.breakPoint(BreakPoints.TYPE_APPLICATION_CREATE);
        Log.v(TAG, "onCreate Finished.");
    }
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/task/LaunchTask.java<|end_filename|>
package com.ryan.github.launcher.task;

import com.ryan.github.launcher.IAppLauncher;
import com.ryan.github.launcher.executor.Schedulers;

import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public abstract class LaunchTask implements ILaunchTask {

    private static final int STATE_CREATE = 0;
    private static final int STATE_WAITING = 1;
    private static final int STATE_RUNNING = 2;
    private static final int STATE_FINISHED = 3;

    private final Set<ILaunchTask> mChildTask;
    private CountDownLatch mDependsOnLatch;
    private IAppLauncher mContextLauncher;
    private int mState = STATE_CREATE;

    public LaunchTask() {
        mChildTask = new HashSet<>();
    }

    @Override
    public final void run() {
        markState(STATE_WAITING);
        waitToSatisfy();
        markState(STATE_RUNNING);
        call();
        markState(STATE_FINISHED);
        notifyChildren();
        notifyLauncher();
    }

    protected abstract void call();

    @Override
    public List<Class<? extends ILaunchTask>> dependsOn() {
        return null;
    }

    @Override
    public Schedulers runOn() {
        return Schedulers.COMPUTATION;
    }

    private void waitToSatisfy() {
        if (mDependsOnLatch != null) {
            try {
                mDependsOnLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void satisfy() {
        if (mDependsOnLatch != null) {
            mDependsOnLatch.countDown();
        }
    }

    private void notifyChildren() {
        if (!mChildTask.isEmpty()) {
            for (ILaunchTask task : mChildTask) {
                task.satisfy();
            }
        }
    }

    private void notifyLauncher() {
        if (mContextLauncher != null) {
            List<String> breakPoints = finishBeforeBreakPoints();
            if (breakPoints != null && !breakPoints.isEmpty()) {
                for (String breakPoint : breakPoints) {
                    mContextLauncher.satisfyBreakPoint(breakPoint);
                }
            }
            mContextLauncher.onceTaskFinish();
        }
    }

    @Override
    public void addChildTask(ILaunchTask task) {
        mChildTask.add(task);
    }

    protected String getDependsOnString() {
        if (dependsOn() == null || dependsOn().isEmpty()) {
            return "";
        }
        StringBuilder output = new StringBuilder();
        for (Class clazz : dependsOn()) {
            output.append(clazz.getSimpleName());
            output.append(" | ");
        }
        return output.toString();
    }

    protected String getThreadName() {
        return Thread.currentThread().getName();
    }

    protected void randomSleepTest() {
        int random = new Random().nextInt(5) + 1;
        try {
            Thread.sleep(random * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void attachContext(IAppLauncher launcher) {
        mContextLauncher = launcher;
    }

    @Override
    public boolean isFinished() {
        return mState == STATE_FINISHED;
    }

    private void markState(int state) {
        mState = state;
    }

    @Override
    public void updateDependsCount(int count) {
        mDependsOnLatch = new CountDownLatch(count);
    }

    @Override
    public List<String> finishBeforeBreakPoints() {
        return null;
    }
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/listener/IdleHandler.java<|end_filename|>
package com.ryan.github.launcher.listener;

/**
 * created by 2019/7/2 1:05 AM
 *
 * @author Ryan
 */
public interface IdleHandler {

    void onIdle();
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/task/TaskSortUtil.java<|end_filename|>
package com.ryan.github.launcher.task;

import android.support.annotation.NonNull;
import android.support.v4.util.ArraySet;
import android.util.Log;

import com.ryan.github.launcher.BuildConfig;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * sort all tasks.
 *
 * Created by Ryan
 * at 2019/7/1
 */
public class TaskSortUtil {

    private static final String TAG = TaskSortUtil.class.getSimpleName();

    public static synchronized List<ILaunchTask> getSortResult(List<ILaunchTask> normalTasks,
                                                               List<ILaunchTask> headTasks,
                                                               List<ILaunchTask> tailTasks) {
        int headTasksSize = headTasks.size();
        int normalTasksSize = normalTasks.size();
        int mergeTasksSize = normalTasks.size() + headTasksSize + tailTasks.size();
        List<ILaunchTask> mergeTasksList = new ArrayList<>(mergeTasksSize);
        mergeTasksList.addAll(headTasks);
        mergeTasksList.addAll(normalTasks);
        mergeTasksList.addAll(tailTasks);

        List<Class<? extends ILaunchTask>> mergeClassList = cloneClassList(mergeTasksList);
        List<Class<? extends ILaunchTask>> headClassList = cloneClassList(headTasks);
        List<Class<? extends ILaunchTask>> midClassList = cloneClassList(normalTasks);

        Set<Integer> dependSet = new ArraySet<>();
        TaskGraph graph = new TaskGraph(mergeTasksSize);

        int tailTaskStartIndex = headTasksSize + normalTasksSize;

        for (int i = 0; i < mergeTasksList.size(); i++) {
            ILaunchTask task = mergeTasksList.get(i);
            List<Class<? extends ILaunchTask>> dependsTaskClasses = task.dependsOn();
            if (dependsTaskClasses == null) {
                dependsTaskClasses = new ArrayList<>();
            }

            if (i >= headTasksSize && i < tailTaskStartIndex) {
                // process normal tasks
                dependsTaskClasses.addAll(headClassList);
            } else if (i >= headTasksSize + normalTasksSize) {
                // process tail tasks
                dependsTaskClasses.addAll(midClassList);
            }
            if (dependsTaskClasses.isEmpty()) {
                continue;
            }
            task.updateDependsCount(dependsTaskClasses.size());
            for (Class cls : dependsTaskClasses) {
                int dependIndex = mergeClassList.indexOf(cls);
                if (dependIndex < 0) {
                    throw new IllegalStateException(task.getClass().getSimpleName()
                            + " depends on " + cls.getSimpleName()
                            + " can not be found in task list.");
                }
                mergeTasksList.get(dependIndex).addChildTask(task);
                dependSet.add(dependIndex);
                graph.addEdge(dependIndex, i);
            }
        }
        List<Integer> topologicalSortList = graph.topologicalSort();
        return buildSortedTasks(mergeTasksList, dependSet, topologicalSortList);
    }

    private static List<Class<? extends ILaunchTask>> cloneClassList(List<ILaunchTask> tasks) {
        List<Class<? extends ILaunchTask>> clsLaunchTasks = new ArrayList<>();
        for (ILaunchTask task : tasks) {
            clsLaunchTasks.add(task.getClass());
        }
        return clsLaunchTasks;
    }

    @NonNull
    private static List<ILaunchTask> buildSortedTasks(List<ILaunchTask> tasks,
                                                      Set<Integer> dependSet,
                                                      List<Integer> topologicalSortList) {
        int totalSize = tasks.size();
        int dependedSize = dependSet.size();
        List<ILaunchTask> sortedTask = new ArrayList<>(totalSize);
        List<ILaunchTask> tasksDepended = new ArrayList<>(dependedSize);
        List<ILaunchTask> tasksWithoutDepend = new ArrayList<>(totalSize - dependedSize);
        for (int index : topologicalSortList) {
            if (dependSet.contains(index)) {
                tasksDepended.add(tasks.get(index));
            } else {
                ILaunchTask task = tasks.get(index);
                tasksWithoutDepend.add(task);
            }
        }
        // Order: head ---> is dependent on others --> no dependencies ---> tail
        sortedTask.addAll(tasksDepended);
        sortedTask.addAll(tasksWithoutDepend);
        debugInfo(sortedTask);
        return sortedTask;
    }

    private static void debugInfo(List<ILaunchTask> newTasksAll) {
        if (BuildConfig.DEBUG) {
            for (ILaunchTask task : newTasksAll) {
                Log.i(TAG, task.getClass().getSimpleName());
            }
        }
    }
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/IAppLauncher.java<|end_filename|>
package com.ryan.github.launcher;

/**
 * Created by Ryan
 * at 2019/7/2
 */
public interface IAppLauncher {

    void breakPoint(String type);

    void breakPoint(String type, int timeout);

    void satisfyBreakPoint(String type);

    void onceTaskFinish();

    void start();

    void shutdown();
}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/SimpleLauncherTask7.java<|end_filename|>
package com.ryan.github.launcher.sample;

import android.util.Log;

import com.ryan.github.launcher.executor.Schedulers;
import com.ryan.github.launcher.task.LaunchTask;

import static com.ryan.github.launcher.sample.Constants.TAG;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class SimpleLauncherTask7 extends LaunchTask {

    @Override
    protected void call() {
        randomSleepTest();
        Log.v(TAG, "SimpleLauncherTask7 run on " + getThreadName());
    }

    @Override
    public Schedulers runOn() {
        return Schedulers.IO;
    }
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/executor/IOExecutor.java<|end_filename|>
package com.ryan.github.launcher.executor;

import android.os.Process;
import android.support.annotation.NonNull;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class IOExecutor implements TaskExecutor {

    private static final String IO_THREAD_PREFIX = "launcher-io-";
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
    private AtomicInteger mName = new AtomicInteger(0);
    private ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, CORE_POOL_SIZE, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
        @Override
        public Thread newThread(@NonNull Runnable r) {
            return new Thread(r, IO_THREAD_PREFIX + mName.incrementAndGet()){
                @Override
                public void run() {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_LESS_FAVORABLE);
                    super.run();
                }
            };
        }
    });

    public static IOExecutor getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final IOExecutor INSTANCE = new IOExecutor();
    }

    private IOExecutor() {
        mExecutor.allowCoreThreadTimeOut(true);
    }

    @Override
    public void execute(Runnable runnable) {
        mExecutor.execute(runnable);
    }

    @Override
    public void shutdown() {
        mExecutor.shutdown();
    }
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/AppLauncher.java<|end_filename|>
package com.ryan.github.launcher;

import android.os.Looper;
import android.os.MessageQueue;

import com.ryan.github.launcher.executor.Executors;
import com.ryan.github.launcher.executor.TaskExecutor;
import com.ryan.github.launcher.listener.IdleHandler;
import com.ryan.github.launcher.task.ILaunchTask;
import com.ryan.github.launcher.task.TaskSortUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class AppLauncher implements IAppLauncher {

    private static final int STATE_PREPARE = 1;
    private static final int STATE_RUNNING = 2;
    private static final int STATE_FINISHED = 3;
    private static final int STATE_SHUTDOWN = 4;
    private final AtomicInteger mFinishedCount;
    private List<ILaunchTask> mLauncherTasks;
    private IdleHandler mIdleHandler;
    private Map<String, CountDownLatch> mBreakPointLatchMap;
    private List<ILaunchTask> mHeadTasks;
    private List<ILaunchTask> mTailTasks;
    private Queue<ILaunchTask> mDelayTasks;
    private Set<TaskExecutor> mExecutors;
    private boolean mShutDownAfterFinish;
    private MessageQueue mMainQueue;
    private volatile int mState = STATE_PREPARE;
    private volatile int mTaskCount;

    private AppLauncher() {
        mFinishedCount = new AtomicInteger(0);
        mExecutors = new HashSet<>();
    }

    @Override
    public void start() {
        checkThread();
        if (mState == STATE_SHUTDOWN) {
            throw new IllegalStateException("the Launcher has been shut down.");
        }
        if (mLauncherTasks == null || mLauncherTasks.isEmpty()) {
            return;
        }
        if (mState == STATE_RUNNING) {
            return;
        }
        if (mMainQueue == null) {
            mMainQueue = Looper.myQueue();
        }
        markState(STATE_RUNNING);
        mLauncherTasks = TaskSortUtil.getSortResult(mLauncherTasks, mHeadTasks, mTailTasks);
        mTaskCount = mLauncherTasks.size();
        executeTasks(mLauncherTasks);
    }

    @Override
    public void shutdown() {
        if (mState == STATE_SHUTDOWN) {
            return;
        }
        switch (mState) {
            case STATE_RUNNING:
                mShutDownAfterFinish = true;
                break;
            case STATE_FINISHED:
                shutdownAllExecutors();
            default:
                markState(STATE_SHUTDOWN);
        }
    }

    private synchronized void shutdownAllExecutors() {
        if (mExecutors.isEmpty()) {
            return;
        }
        for (TaskExecutor executor : mExecutors) {
            executor.shutdown();
        }
        mExecutors.clear();
        mExecutors = null;
    }

    @Override
    public void satisfyBreakPoint(String type) {
        CountDownLatch latch = getBreakPointLatch(type);
        if (latch != null) {
            latch.countDown();
        }
    }

    @Override
    public void onceTaskFinish() {
        if (mFinishedCount.incrementAndGet() == mTaskCount) {
            markState(STATE_FINISHED);
            handleOnFinished();
            handDelayTasks();
        }
    }

    private void handleOnFinished() {
        if (mIdleHandler != null) {
            mIdleHandler.onIdle();
        }
        if (mShutDownAfterFinish) {
            shutdown();
        }
    }

    private void handDelayTasks() {
        if (mMainQueue == null || mState == STATE_PREPARE) {
            throw new IllegalStateException("The launcher has not started yet.");
        }
        if (mState == STATE_SHUTDOWN){
            throw new IllegalStateException("The launcher has been shut down.");
        }
        mMainQueue.addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                ILaunchTask task = mDelayTasks.poll();
                executeTasks(task);
                return !mDelayTasks.isEmpty();
            }
        });
    }

    private int countOfNeedWaitTask(String type) {
        int count = 0;
        for (ILaunchTask task : mLauncherTasks) {
            if (!task.isFinished()) {
                List<String> breakPoints = task.finishBeforeBreakPoints();
                if (breakPoints != null && breakPoints.contains(type)) {
                    ++count;
                }
            }
        }
        return count;
    }

    @Override
    public void breakPoint(String type) {
        breakPoint(type, 0);
    }

    @Override
    public void breakPoint(String type, int timeout) {
        int count = countOfNeedWaitTask(type);
        if (count > 0) {
            CountDownLatch breakPointLatch = obtainBreakPointLatch(type, count);
            try {
                if (timeout > 0) {
                    breakPointLatch.await(timeout, TimeUnit.MILLISECONDS);
                } else {
                    breakPointLatch.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized CountDownLatch obtainBreakPointLatch(String type, int count) {
        if (mBreakPointLatchMap == null) {
            mBreakPointLatchMap = new ConcurrentHashMap<>();
        }
        CountDownLatch latch = mBreakPointLatchMap.get(type);
        if (latch == null) {
            latch = new CountDownLatch(count);
            mBreakPointLatchMap.put(type, latch);
        }
        return latch;
    }

    private CountDownLatch getBreakPointLatch(String type) {
        if (mBreakPointLatchMap == null || mBreakPointLatchMap.isEmpty()) {
            return null;
        }
        return mBreakPointLatchMap.get(type);
    }

    public static final class Builder {

        private List<ILaunchTask> mLauncherTasks;
        private IdleHandler mIdleHandler;
        private List<ILaunchTask> mHeadTasks;
        private List<ILaunchTask> mTailTasks;
        private Queue<ILaunchTask> mDelayTasks;

        public Builder() {
            mLauncherTasks = new ArrayList<>();
            mHeadTasks = new ArrayList<>();
            mTailTasks = new ArrayList<>();
            mDelayTasks = new LinkedList<>();
        }

        public Builder addTask(ILaunchTask task) {
            mLauncherTasks.add(task);
            return this;
        }

        public Builder idleHandler(IdleHandler handler) {
            mIdleHandler = handler;
            return this;
        }

        public Builder addHeadTask(ILaunchTask task) {
            mHeadTasks.add(0, task);
            return this;
        }

        public Builder addTailTask(ILaunchTask task) {
            mTailTasks.add(task);
            return this;
        }

        public Builder addDelayTask(ILaunchTask task) {
            mDelayTasks.offer(task);
            return this;
        }

        public AppLauncher create() {
            AppLauncher launcher = new AppLauncher();
            launcher.mLauncherTasks = mLauncherTasks;
            launcher.mIdleHandler = mIdleHandler;
            launcher.mHeadTasks = mHeadTasks;
            launcher.mTailTasks = mTailTasks;
            launcher.mDelayTasks = mDelayTasks;
            return launcher;
        }

        public AppLauncher start() {
            AppLauncher launcher = create();
            launcher.start();
            return launcher;
        }

    }

    private void markState(int state) {
        mState = state;
    }

    private void executeTasks(List<ILaunchTask> tasks) {
        for (ILaunchTask task : tasks) {
            executeTasks(task);
        }
    }

    private void executeTasks(ILaunchTask task) {
        task.attachContext(this);
        TaskExecutor executor = Executors.get(task.runOn());
        mExecutors.add(executor);
        executor.execute(task);
    }

    private void checkThread() {
        if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
            throw new IllegalStateException("AppLauncher.start() must be executed on the main thread.");
        }
    }
}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/SimpleLauncherTask4.java<|end_filename|>
package com.ryan.github.launcher.sample;

import android.util.Log;

import com.ryan.github.launcher.task.LaunchTask;
import com.ryan.github.launcher.task.ILaunchTask;

import java.util.ArrayList;
import java.util.List;

import static com.ryan.github.launcher.sample.Constants.TAG;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class SimpleLauncherTask4 extends LaunchTask {

    @Override
    public List<Class<? extends ILaunchTask>> dependsOn() {
        List<Class<? extends ILaunchTask>> dependsOn = new ArrayList<>();
        dependsOn.add(SimpleLauncherTask7.class);
        return dependsOn;
    }

    @Override
    protected void call() {
        randomSleepTest();
        Log.v(TAG, "SimpleLauncherTask4 run on " + getThreadName() + ", depends on " + getDependsOnString());
    }

}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/executor/TaskExecutor.java<|end_filename|>
package com.ryan.github.launcher.executor;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public interface TaskExecutor {

    void execute(Runnable runnable);

    void shutdown();

}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/SimpleLauncherTask11.java<|end_filename|>
package com.ryan.github.launcher.sample;

import android.util.Log;

import com.ryan.github.launcher.task.LaunchTask;

import static com.ryan.github.launcher.sample.Constants.TAG;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class SimpleLauncherTask11 extends LaunchTask {

    @Override
    protected void call() {
        randomSleepTest();
        Log.v(TAG, getClass().getSimpleName() + " run on " + getThreadName() + ", depends on " + getDependsOnString());
    }

}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/BreakPoints.java<|end_filename|>
package com.ryan.github.launcher.sample;

/**
 * Created by Ryan
 * at 2019/7/9
 */
class BreakPoints {

    static final String TYPE_APPLICATION_CREATE = "ApplicationOnCreate";

}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/task/ILaunchTask.java<|end_filename|>
package com.ryan.github.launcher.task;

import com.ryan.github.launcher.IAppLauncher;
import com.ryan.github.launcher.executor.Schedulers;

import java.util.List;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public interface ILaunchTask extends Runnable {

    List<Class<? extends ILaunchTask>> dependsOn();

    Schedulers runOn();

    void satisfy();

    void addChildTask(ILaunchTask task);

    List<String> finishBeforeBreakPoints();

    void attachContext(IAppLauncher launcher);

    boolean isFinished();

    void updateDependsCount(int count);
}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/executor/Executors.java<|end_filename|>
package com.ryan.github.launcher.executor;

/**
 * Created by Ryan
 * at 2019/7/1
 */
public class Executors {

    public static TaskExecutor get(Schedulers schedulers) {
        TaskExecutor executor;
        switch (schedulers) {
            case IO:
                executor = IOExecutor.getInstance();
                break;
            case MAIN:
                executor = MainExecutor.getInstance();
                break;
            case COMPUTATION:
            default:
                executor = ComputeExecutor.getInstance();
        }
        return executor;
    }

}


<|start_filename|>launcher/src/main/java/com/ryan/github/launcher/executor/Schedulers.java<|end_filename|>
package com.ryan.github.launcher.executor;

/**
 * created by 2019/7/2 12:12 AM
 *
 * @author Ryan
 */
public enum Schedulers {

    MAIN,
    IO,
    COMPUTATION
}


<|start_filename|>app/src/main/java/com/ryan/github/launcher/sample/Constants.java<|end_filename|>
package com.ryan.github.launcher.sample;

/**
 * Created by Ryan
 * at 2019/7/2
 */
public class Constants {

    public static final String TAG = "LauncherSample";
}
