package com.datdo.mobilib.util; import java.util.ArrayList; import java.util.List; /** * <pre> * Tiny but very useful. Every instance of this class is a queue which you can push any task into it and wait for them to complete one after one. * Task is defined by implementing <code>MblSerializer#Task</code> interface. * Task is always invoked in main thread, then it can split processing to another thread itself if needed. * * Sample code: * * {@code * MblSerializer s = new MblSerializer(); * * s.run(new MblSerializer.Task() { * @Override * public void run(Runnable finishCallback) { * // run task 1 in async thread * MblUtils.executeOnAsyncThread(new Runnable() { * // ... do something here * * // finally, invoke callback * finishCallback.run(); * }); * } * }); * * s.run(new MblSerializer.Task() { * @Override * public void run(Runnable finishCallback) { * // run task 2 in async thread * MblUtils.executeOnAsyncThread(new Runnable() { * // ... do something here * * // finally, invoke callback * finishCallback.run(); * }); * } * }); * * // ... next task/action comes here * } * </pre> */ public class MblSerializer { /** * Interface to define a task. */ public static interface Task { public void run(Runnable finishCallback); } private final List<Task> mTasks = new ArrayList<Task>(); private boolean mIsRunning = false; private final Runnable mFinishCallback = new Runnable() { @Override public void run() { mIsRunning = false; runNextTask(); } }; private void runNextTask() { // post to main thread to prevent StackOverFlow MblUtils.getMainThreadHandler().post(new Runnable() { @Override public void run() { synchronized (MblSerializer.this) { if (!mIsRunning && !mTasks.isEmpty()) { mIsRunning = true; mTasks.remove(0).run(mFinishCallback); } } } }); } /** * <pre> * Add a task to queue. * Task is run immediately if no task is running, otherwise wait for its turn. * </pre> */ public void run(Task task) { synchronized (this) { mTasks.add(task); runNextTask(); } } /** * <pre> * Create a super task that wraps sub-tabs, then call {@link #run(Task)} to add super task to queue. * Sub-tasks is executed parallel inside super task. Super task will automatically finish its life right after all sub-tasks is completed. * </pre> */ public void run(final Task... subtasks) { Task superTask = new Task() { @Override public void run(final Runnable finishCallback) { if (MblUtils.isEmpty(subtasks)) { finishCallback.run(); return; } Runnable hookedFinishCallback = new Runnable() { int count = 0; @Override public void run() { MblUtils.executeOnMainThread(new Runnable() { @Override public void run() { count++; if (count == subtasks.length) { finishCallback.run(); } } }); } }; for (Task t : subtasks) { t.run(hookedFinishCallback); } } }; run(superTask); } /** * Cancel a specific task. * @return true if task exists in queue */ public boolean cancel(Task task) { synchronized (this) { return mTasks.remove(task); } } /** * Cancel all tasks. */ public void cancelAll() { synchronized (this) { mTasks.clear(); } } }