package com.door43.tools.reporting; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * This is the base class for creating a managed thread. * Managed threads are designed to be used in the ThreadManager. * Managing threads allows you to keep track of threads throughout your application during activity de/re-construction */ public abstract class ManagedTask implements Runnable { private Thread mThread; private boolean mFinished; private List mFinishListeners = Collections.synchronizedList(new ArrayList<>()); private Object mTaskId; private List mProgressListeners = Collections.synchronizedList(new ArrayList<>()); private double mProgress = -1; private String mProgressMessage = ""; private boolean mIsStopped = false; private List mStartListeners = Collections.synchronizedList(new ArrayList<>()); private boolean mIsRunning = false; private List mOnIdChangedListeners = Collections.synchronizedList(new ArrayList<>()); protected int mThreadPriority = android.os.Process.THREAD_PRIORITY_BACKGROUND; public ManagedTask ManagedTask() { return this; } /** * Changes the thread priority. e.g. android.os.Process.THREAD_PRIORITY_BACKGROUND * @param priority the priority of this task default is THREAD_PRIORITY_BACKGROUND */ protected final void setThreadPriority(int priority) { mThreadPriority = priority; } @Override public final void run() { android.os.Process.setThreadPriority(mThreadPriority); mThread = Thread.currentThread(); try { if(Thread.interrupted()) { throw new InterruptedException(); } mIsRunning = true; synchronized (mStartListeners) { Iterator<OnStartListener> it = mStartListeners.iterator(); while(it.hasNext()) { try { it.next().onStart(this); } catch (Exception e) { e.printStackTrace(); } } } start(); } catch (InterruptedException e) { } finally { // clears the thread's interrupt flag Thread.interrupted(); } mIsRunning = false; mFinished = true; synchronized (mFinishListeners) { Iterator<OnFinishedListener> it = mFinishListeners.iterator(); while(it.hasNext()) { try { it.next().onFinished(this); } catch (Exception e) { e.printStackTrace(); } } } onStop(); } public final void run(Thread thread) { mThread = thread; start(); } /** * Causes the task to sleep * @param time The time to sleep in milliseconds. * @throws InterruptedException */ protected final void sleep(long time) { try { Thread.sleep(time); } catch (InterruptedException e) { } finally { // clear the thread's interrupt flag Thread.interrupted(); } } /** * Utility method to chain several tasks together * @param task */ public ManagedTask then(ManagedTask task) { delegate(task); return task; } /** * Executes another task on the same thread. * Progress listeners are inherited from the delegating task * @param task */ protected final void delegate(ManagedTask task) { synchronized (mProgressListeners) { Iterator<OnProgressListener> it = mProgressListeners.iterator(); while(it.hasNext()) { task.addOnProgressListener(it.next()); } } task.run(mThread); } /** * Sets the task id * @param id */ public final void setTaskId(Object id) { mTaskId = id; synchronized (mOnIdChangedListeners) { Iterator<OnIdChangedListener> it = mOnIdChangedListeners.iterator(); while(it.hasNext()) { try { it.next().onChanged(this); } catch (Exception e) { e.printStackTrace(); } } } } /** * Returns the task id * @return */ public final Object getTaskId() { return mTaskId; } /** * Called when progress has been made. * This method should be called manually by the implementing class to update the progress * @param progress the progress being made between 1 and 0 * @param message the progress message */ protected final void publishProgress(double progress, String message) { mProgress = progress; mProgressMessage = message; if(!isFinished()) { synchronized (mProgressListeners) { Iterator<OnProgressListener> it = mProgressListeners.iterator(); while(it.hasNext()) { try { it.next().onProgress(this, mProgress, mProgressMessage); } catch (Exception e) { e.printStackTrace(); } } } } } /** * Sets the listener to be called on progress updates * @param listener */ public final void addOnProgressListener(OnProgressListener listener) { if(!mProgressListeners.contains(listener) && listener != null) { mProgressListeners.add(listener); if(!isFinished()) { try { listener.onProgress(this, mProgress, mProgressMessage); } catch (Exception e) { e.printStackTrace(); } } } } /** * Sets the listener to be called when the task's id changes * This is useful when you need to begin working with a task object before it has been * loaded into the task manager * @param listener */ public final void addOnIdChangedListener(OnIdChangedListener listener) { if(!mOnIdChangedListeners.contains(listener) && listener != null) { mOnIdChangedListeners.add(listener); try { listener.onChanged(this); } catch (Exception e) { e.printStackTrace(); } } } /** * Removes the on id changed listener * @param listener */ public final void removeOnIdChangedListener(OnIdChangedListener listener) { mOnIdChangedListeners.remove(listener); } /** * Removes the on progress listener * @param listener */ public final void removeOnProgressListener(OnProgressListener listener) { mProgressListeners.remove(listener); } /** * Sets the listener to be called when the task is finished * @param listener */ public final void addOnFinishedListener(OnFinishedListener listener) { if(!mFinishListeners.contains(listener) && listener != null) { mFinishListeners.add(listener); if (isFinished()) { try { listener.onFinished(this); } catch (Exception e) { e.printStackTrace(); } } } } /** * Removes the on finished listener * @param listener */ public final void removeOnFinishedListener(OnFinishedListener listener) { mFinishListeners.remove(listener); } /** * Sets the listener to be called when the task starts * @param listener */ public final void addOnStartListener(OnStartListener listener) { if(!mStartListeners.contains(listener) && listener != null) { mStartListeners.add(listener); } } /** * Removes the on start listener * @param listener */ public final void removeOnStartListener(OnStartListener listener) { mStartListeners.remove(listener); } /** * Perform any threadable tasks here */ public abstract void start(); /** * Returns the maximum progress threshold * Useful for setting up progress bars * @return */ public int maxProgress() { return 100; } /** * Returns the thread on which this runnable is being executed * @return */ public final Thread getThread() { return mThread; } /** * Checks if the task has finished running. * @return */ public final boolean isFinished() { return mFinished; } /** * Checks if the task is running * @return */ public final boolean isRunning() { return mIsRunning; } /** * Checks if the task was canceled * @return */ public final boolean isCanceled() { return mIsStopped; } /** * Notifies the task that it should stop as soon as possible. */ public final void stop() { mIsStopped = true; } /** * Same as stop except it also removes all of the listeners */ public final void destroy() { mIsStopped = true; mStartListeners.clear(); mFinishListeners.clear(); mProgressListeners.clear(); } /** * Called whenever the task stops completely. * This allows tasks to perform any cleanup operations */ protected void onStop() { } /** * Checks if the task has been interrupted. * Interrupting threads is not reliable so we need to set a flag. * @return */ public final boolean interrupted() { if(mThread != null) { return mThread.isInterrupted() || mIsStopped; } else { return mIsStopped; } } public interface OnFinishedListener { void onFinished(ManagedTask task); } public interface OnProgressListener { void onProgress(ManagedTask task, double progress, String message); } public interface OnStartListener { void onStart(ManagedTask task); } public interface OnIdChangedListener { void onChanged(ManagedTask task); } }