編輯:關於Android編程
考慮如下情況:
情況1:
訪問網絡(或其他耗時的事情)。通常的做法是:
1、顯示一個ProgressDialog對話框,提示用戶。
2、啟動工作線程來執行耗時操作。
3、發送消息到關聯到主線程的Handler裡面,關閉對話框。
情況2:
從網絡下載一個zip文件,下載完成之後,詢問用戶是否執行解壓操作。通常的合理做法:
1、顯示一個ProgressDialog對話框,提示用戶。
2、啟動線程執行下載操作。
3、發送消息到關聯到主線程的Handler裡面,關閉對話框,然後啟動一個詢問對話框。
4、用戶如果點擊[YES],顯示一個ProgressDialog對話框。
5、啟動用線程執行解壓操作。
6、發送消息到關聯到主線程的Handler裡面,關閉對話框。
通常情況下,在Android我們有兩種方式來使用線程,一是Thread + Handler這種標准方式,另外一種是使用AsyncTask類。
實現這兩個情況的缺點:
1、定義Handler,發送消息,使得代碼變得復雜,不易理解。
2、發送消息是異步處理,在某些情況下可能需要做等待操作。
3、流程執行混亂,不是流水作業。
基於以上情況,我們能不能也像流水線的操作那麼調用我們的回調(Callback),使用者只關心第一步干什麼,第二步干什麼,如果能這樣的話,那麼在哪步做什麼都能明確定義出來,這就是鏈式調用。
請看下面的鏈式調用的寫法(JavaScript):
[java]
Async.go(initialArgument)
.next(firstAsyncOperation)
.next(secondAsyncOperation)
.next(thirdAsyncOperation)
.next(function(finalResult) { alert(finalResult); })
Async.go(initialArgument)
.next(firstAsyncOperation)
.next(secondAsyncOperation)
.next(thirdAsyncOperation)
.next(function(finalResult) { alert(finalResult); })
用戶只需要添加每一步的task到一個隊列裡面,然後執行,這些task就會按添加的順序執行,從而實現鏈式調用。
這種思想還不挺好的,在寫代碼的時候,我們更加關注實現的邏輯,不需要去考慮發什麼消息等。只考慮第一步干什麼,第二步干什麼等。這樣在以後代碼維護時也比較好。
我們能不能設計出一個Android版本的異步鏈式調用的模塊呢,請看下面。
Task
我們抽象出每一步要做的事情,定義一個Task類,它是一個抽象類,有如下核心屬性和方法:
mRunInBackground
用來指示這個Task是運行在後台線程還是運行在主線程。
onExecuter(TaskOperation)
我們需要實現該方法,在這裡面執行我們想要做的事情。
onProgressUpdate(Object)
我們可以重寫該方法,來更新我們所做事情的進度,這個方法運行在主線程。
注意:在使用時,你必須指定這個Task是運行在UI線程還是後台線程。
TaskOperation
1)這個類裡面包含了task的運行參數,上一個task的輸出將會作為下一個task的輸入。
2)它可以指示繼續或暫停執行下一個task。
3)它裡面使用了一個object[]來存儲參數。
TaskManager
1)管理task隊列,始終從隊列第一個開始執行,執行一個task後,這個task將從隊列出移除。
2)內部創建了一個帶有消息循環的線程。
3)執行task時,判斷其運行的線程環境,如果運行在UI線程,發送消息到UI的Handler來執行。
4)內部封裝了Handler,用戶不用關心是否發送消息。
5)核心方法有:
- next(Task)
- execute()
- execute(TaskOperation)
- cancelCurrentTask()
- removeTasks()
- publishProgress(Object)
這裡只是給了一個最基本的設計思路,現在該設計還有完善的地方,具體的實現請參考相關的代碼和測試工程。
實現代碼
Task.java
[java]
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong
*
*/
package com.nj1s.lib.task;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* <p>
* This method define the task used to do something. Typically you should override
* {@link #onExecute(TaskOperation)} method to do you things, on the other hand, you
* also can override the {@link #onProgressUpdate(Object)} method to get the progress of
* you things.
* </p>
*
* <p>
* NOTE:
* There is an very important thing you should pay attention to, you must specify the task
* is running on background thread or UI thread, the default flag is true ---- running on
* background thread.
* </p>
*
* @author LeeHong
*
* @date 2012/10/30
*/
public abstract class Task
{
/**
* The id of the task, typically you need NOT set it, if will set automatically when you
* add this task into {@link TaskManager} class.
*/
private int mId = 0;
/**
* The task name.
*/
private String mName = null;
/**
* Indicate this task is canceled or not.
*/
private AtomicBoolean mCancelled = new AtomicBoolean(false);
/**
* The task status, default value is {@link Status#PENDING}.
*/
private volatile Status mStatus = Status.PENDING;
/**
* The running status, default value is {@link RunningStatus#UI_THREAD}.
*/
private volatile RunningStatus mRunStatus = RunningStatus.UI_THREAD;
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/
public enum Status
{
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link Task#onExecute} has finished.
*/
FINISHED,
}
/**
* Indicate the task running status.
*/
public enum RunningStatus
{
/**
* Indicate the task is running in the background thread.
*/
WORK_THREAD,
/**
* Indicate the task is running in the UI thread.
*/
UI_THREAD,
}
/**
* The constructor method.
*
* @param runInBackground
* @param name
*/
public Task(Task task)
{
this.mRunStatus = task.mRunStatus;
this.mName = task.mName;
this.mStatus = task.mStatus;
}
/**
* The constructor method.
*
* @param status indicate the task is running in background thread or not.
*/
public Task(RunningStatus status)
{
this(status, null);
}
/**
* The constructor method.
*
* @param runInBackground
* @param name
*/
public Task(RunningStatus status, String name)
{
mRunStatus = status;
mName = name;
}
/**
* Override this method to do you works.
*
* @param operation The operation is passed from previous task.
*
* @return Typically you should return the {@link #operation}.
*/
public abstract TaskOperation onExecute(TaskOperation operation);
/**
* Called when change the progress, this method is running in UI thread.
*
* @param progresses
*/
public void onProgressUpdate(Object progresses)
{
}
/**
* Cancel the task.
*/
public void cancel()
{
mCancelled.set(true);
}
/**
* Indicate the task is canceled or not.
*
* @return
*/
public boolean isCancelled()
{
return mCancelled.get();
}
/**
* Get the running status.
*
* @return
*/
public RunningStatus getRunningStatus()
{
return mRunStatus;
}
/**
* Set the name of the task.
*
* @param name The task name.
*/
public void setTaskName(String name)
{
mName = name;
}
/**
* Get the task name.
*
* @return the task name.
*/
public String getTaskName()
{
return mName;
}
/**
* Set the status of the task.
*
* @param status
*/
public void setStatus(Status status)
{
mStatus = status;
}
/**
* Get the status of the task.
*
* @return
*/
public Status getStatus()
{
return mStatus;
}
/**
* Set the id of the task.
*
* @param id
*/
public void setTaskId(int id)
{
mId = id;
}
/**
* Get the task id.
*/
public int getTaskId()
{
return mId;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("name = ").append(mName).append(" ");
sb.append("id = ").append(mId).append(" ");
sb.append(super.toString());
return sb.toString();
}
}
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong
*
*/
package com.nj1s.lib.task;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* <p>
* This method define the task used to do something. Typically you should override
* {@link #onExecute(TaskOperation)} method to do you things, on the other hand, you
* also can override the {@link #onProgressUpdate(Object)} method to get the progress of
* you things.
* </p>
*
* <p>
* NOTE:
* There is an very important thing you should pay attention to, you must specify the task
* is running on background thread or UI thread, the default flag is true ---- running on
* background thread.
* </p>
*
* @author LeeHong
*
* @date 2012/10/30
*/
public abstract class Task
{
/**
* The id of the task, typically you need NOT set it, if will set automatically when you
* add this task into {@link TaskManager} class.
*/
private int mId = 0;
/**
* The task name.
*/
private String mName = null;
/**
* Indicate this task is canceled or not.
*/
private AtomicBoolean mCancelled = new AtomicBoolean(false);
/**
* The task status, default value is {@link Status#PENDING}.
*/
private volatile Status mStatus = Status.PENDING;
/**
* The running status, default value is {@link RunningStatus#UI_THREAD}.
*/
private volatile RunningStatus mRunStatus = RunningStatus.UI_THREAD;
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/
public enum Status
{
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link Task#onExecute} has finished.
*/
FINISHED,
}
/**
* Indicate the task running status.
*/
public enum RunningStatus
{
/**
* Indicate the task is running in the background thread.
*/
WORK_THREAD,
/**
* Indicate the task is running in the UI thread.
*/
UI_THREAD,
}
/**
* The constructor method.
*
* @param runInBackground
* @param name
*/
public Task(Task task)
{
this.mRunStatus = task.mRunStatus;
this.mName = task.mName;
this.mStatus = task.mStatus;
}
/**
* The constructor method.
*
* @param status indicate the task is running in background thread or not.
*/
public Task(RunningStatus status)
{
this(status, null);
}
/**
* The constructor method.
*
* @param runInBackground
* @param name
*/
public Task(RunningStatus status, String name)
{
mRunStatus = status;
mName = name;
}
/**
* Override this method to do you works.
*
* @param operation The operation is passed from previous task.
*
* @return Typically you should return the {@link #operation}.
*/
public abstract TaskOperation onExecute(TaskOperation operation);
/**
* Called when change the progress, this method is running in UI thread.
*
* @param progresses
*/
public void onProgressUpdate(Object progresses)
{
}
/**
* Cancel the task.
*/
public void cancel()
{
mCancelled.set(true);
}
/**
* Indicate the task is canceled or not.
*
* @return
*/
public boolean isCancelled()
{
return mCancelled.get();
}
/**
* Get the running status.
*
* @return
*/
public RunningStatus getRunningStatus()
{
return mRunStatus;
}
/**
* Set the name of the task.
*
* @param name The task name.
*/
public void setTaskName(String name)
{
mName = name;
}
/**
* Get the task name.
*
* @return the task name.
*/
public String getTaskName()
{
return mName;
}
/**
* Set the status of the task.
*
* @param status
*/
public void setStatus(Status status)
{
mStatus = status;
}
/**
* Get the status of the task.
*
* @return
*/
public Status getStatus()
{
return mStatus;
}
/**
* Set the id of the task.
*
* @param id
*/
public void setTaskId(int id)
{
mId = id;
}
/**
* Get the task id.
*/
public int getTaskId()
{
return mId;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("name = ").append(mName).append(" ");
sb.append("id = ").append(mId).append(" ");
sb.append(super.toString());
return sb.toString();
}
}
TaskOperation.java
[java]
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong.
*/
package com.nj1s.lib.task;
import java.util.ArrayList;
import com.nj1s.lib.task.TaskManager.TaskManagerState;
/**
* The task operation, it wraps the task parameter, etc.
*
* @author LeeHong
*
* @date 2012/10/30
*/
public class TaskOperation
{
/**
* The task parameter.
*/
private Object[] mNextTaskParams = null;
/**
* The task manager status.
*/
private TaskManagerState mTaskManagerStatus = TaskManagerState.CONTINUE;
/**
* The constructor method.
*/
public TaskOperation()
{
}
/**
* The constructor method.
*
* @param nextTaskParams
*/
public TaskOperation(Object[] nextTaskParams)
{
mNextTaskParams = nextTaskParams;
}
/**
* The constructor method.
*
* @param operation
*/
public TaskOperation(TaskOperation operation)
{
setTaskParams(operation);
}
/**
* Get the task parameter.
*/
public Object[] getTaskParams()
{
return mNextTaskParams;
}
/**
* Set the task parameter.
*
* @param params
*/
public void setTaskParams(Object[] params)
{
mNextTaskParams = params;
}
/**
* Set the task parameters.
*
* @param operation
*/
public void setTaskParams(TaskOperation operation)
{
if (operation == this)
{
throw new IllegalArgumentException("The argument can NOT be self.");
}
if (null == operation)
{
return;
}
Object[] params = operation.getTaskParams();
if (null == params)
{
return;
}
ArrayList<Object> paramsList = new ArrayList<Object>();
if (null != mNextTaskParams)
{
for (Object param : mNextTaskParams)
{
paramsList.add(param);
}
}
for (Object param : params)
{
paramsList.add(param);
}
mNextTaskParams = paramsList.toArray();
}
/**
* @param status the mTaskManagerStatus to set
*/
public void setTaskManagerStatus(TaskManagerState status)
{
mTaskManagerStatus = status;
}
/**
* @return the mTaskManagerStatus
*/
public TaskManagerState getTaskManagerStatus()
{
return mTaskManagerStatus;
}
/**
* Append the specified parameter to the end of the parameter list.
*
* @param param
*/
public void appendTaskParam(Object param)
{
appendTaskParams(new Object[] {param});
}
/**
* Append the specified parameter to the end of the parameter list.
*
* @param params
*/
public void appendTaskParams(Object[] params)
{
if (null != params)
{
TaskOperation operation = new TaskOperation(params);
setTaskParams(operation);
}
}
}
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong.
*/
package com.nj1s.lib.task;
import java.util.ArrayList;
import com.nj1s.lib.task.TaskManager.TaskManagerState;
/**
* The task operation, it wraps the task parameter, etc.
*
* @author LeeHong
*
* @date 2012/10/30
*/
public class TaskOperation
{
/**
* The task parameter.
*/
private Object[] mNextTaskParams = null;
/**
* The task manager status.
*/
private TaskManagerState mTaskManagerStatus = TaskManagerState.CONTINUE;
/**
* The constructor method.
*/
public TaskOperation()
{
}
/**
* The constructor method.
*
* @param nextTaskParams
*/
public TaskOperation(Object[] nextTaskParams)
{
mNextTaskParams = nextTaskParams;
}
/**
* The constructor method.
*
* @param operation
*/
public TaskOperation(TaskOperation operation)
{
setTaskParams(operation);
}
/**
* Get the task parameter.
*/
public Object[] getTaskParams()
{
return mNextTaskParams;
}
/**
* Set the task parameter.
*
* @param params
*/
public void setTaskParams(Object[] params)
{
mNextTaskParams = params;
}
/**
* Set the task parameters.
*
* @param operation
*/
public void setTaskParams(TaskOperation operation)
{
if (operation == this)
{
throw new IllegalArgumentException("The argument can NOT be self.");
}
if (null == operation)
{
return;
}
Object[] params = operation.getTaskParams();
if (null == params)
{
return;
}
ArrayList<Object> paramsList = new ArrayList<Object>();
if (null != mNextTaskParams)
{
for (Object param : mNextTaskParams)
{
paramsList.add(param);
}
}
for (Object param : params)
{
paramsList.add(param);
}
mNextTaskParams = paramsList.toArray();
}
/**
* @param status the mTaskManagerStatus to set
*/
public void setTaskManagerStatus(TaskManagerState status)
{
mTaskManagerStatus = status;
}
/**
* @return the mTaskManagerStatus
*/
public TaskManagerState getTaskManagerStatus()
{
return mTaskManagerStatus;
}
/**
* Append the specified parameter to the end of the parameter list.
*
* @param param
*/
public void appendTaskParam(Object param)
{
appendTaskParams(new Object[] {param});
}
/**
* Append the specified parameter to the end of the parameter list.
*
* @param params
*/
public void appendTaskParams(Object[] params)
{
if (null != params)
{
TaskOperation operation = new TaskOperation(params);
setTaskParams(operation);
}
}
}
TaskManager.java
[java]
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong.
*
*/
package com.nj1s.lib.task;
import java.util.HashMap;
import java.util.LinkedList;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.nj1s.lib.task.Task.RunningStatus;
import com.nj1s.lib.task.Task.Status;
import com.nj1s.lib.thread.ThreadWorker;
/**
* This class is used to manager the tasks so that you can add many tasks into the task manger
* and these tasks will be running one by one.
*
* <h2>Example:</h2>
* <pre class="prettyprint">
* private void showProgressDialog()
* {
* final ProgressDialog mProgressDialog = null;
* final TaskManager taskManager = new TaskManager("ShowProgressDlg");
*
* // Set the state change listener.
* taskManager.setStateChangeListener(new IStateChangeListener()
* {
* public void onStateChanged(TaskManager taskManager, State oldState, State newState)
* {
* Toast.makeText(ShowProgressDlgActivity.this, " onStateChanged state = " + newState, Toast.LENGTH_SHORT).show();
* }
* });
*
* taskManager
* .next(new Task(Task.RunningStatus.UI_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* mProgressDialog = new ProgressDialog(ShowProgressDlgActivity.this);
* mProgressDialog.setTitle("Download");
* mProgressDialog.setMessage("Downlonding data from server...");
* mProgressDialog.setCancelable(false);
* mProgressDialog.show();
*
* return null;
* }
* })
* .next(new Task(Task.RunningStatus.WORK_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* // Simulate the work thread.
* sleep(5000);
*
* return null;
* }
* })
* .next(new Task(Task.RunningStatus.UI_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* if (null != mProgressDialog && mProgressDialog.isShowing())
* {
* mProgressDialog.dismiss();
* mProgressDialog = null;
* }
*
* return null;
* }
* })
* .execute(); // Call this method to execute these tasks.
* }
* </pre>
*
* <h2>Note:</h2>
* <pre>
* The {@link Task} class must be specified the task running state, one of the enum {@link Task#RunningStatus}.
* </pre>
*
* @author LeeHong
*
* @date 2012/10/30
*
* @see {@link Task}
* @see {@link TaskOperation}
*/
public class TaskManager
{
/**
* Execute task message.
*/
private static final int MESSAGE_POST_EXECUTE = 0x01;
/**
* Update progress message.
*/
private static final int MESSAGE_POST_PROGRESS = 0x02;
/**
* The state change listener.
*/
public interface IStateChangeListener
{
/**
* Called when the task manager's state is changed. This method will be called in
* UI thread.
*
* @param taskManager Which task manager's state changed.
* @param oldState The old state.
* @param newState The new state.
*/
public void onStateChanged(TaskManager taskManager, State oldState, State newState);
}
/**
* A representation of a task manager's state. A given thread may only be in one
* state at a time.
*/
public enum State
{
/**
* The task manager has been created, but has never been started.
*/
NEW,
/**
* Indicate the task manager is running one task.
*/
RUNNING,
/**
* Indicate the task manager is paused, typically call {@link #pause()} method.
*/
PAUSED,
/**
* All tasks are finished.
*/
FINISHED,
}
/**
* The status of the {@link TaskManager} class.
*/
public enum TaskManagerState
{
/**
* Continue the task manager to run next task.
*/
CONTINUE,
/**
* Indicate the task manager pause to run next task.
*/
PAUSE,
}
/**
* The running task manager collection.
*/
private static HashMap<String, TaskManager> s_taskManagers = new HashMap<String, TaskManager>();
/**
* The task list.
*/
private LinkedList<Task> mTaskList = new LinkedList<Task>();
/**
* The task operation, it will pass from first task to the last task.
*/
private TaskOperation mTaskOperation = new TaskOperation();
/**
* The running thread worker, it own a looper which will be alive until you call
* {@link ThreadWorker#quit()} method.
*/
private ThreadWorker mThreadWorker = null;
/**
* The current perform task, may be null.
*/
private Task mCurTask = null;
/**
* The state of the task manager.
*/
private State mState = State.NEW;
/**
* The name of the task manager.
*/
private String mName = null;
/**
* The listener.
*/
private IStateChangeListener mListener = null;
/**
* The background thread handler, which is associated to a background thread looper.
*/
private Handler mThreadHandler = null;
/**
* The UI thread handler.
*/
private Handler mUIHandler = new Handler(Looper.getMainLooper())
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MESSAGE_POST_EXECUTE:
Task task = (Task)msg.obj;
executeTask(task);
// Try to run next task if possible.
runNextTask();
break;
case MESSAGE_POST_PROGRESS:
postProgress(msg.obj);
break;
}
}
};
/**
* The constructor method.
*/
public TaskManager()
{
}
/**
* The constructor method.
*
* @param name The name of the task manager.
*/
public TaskManager(String name)
{
mName = name;
}
/**
* Add the task to {@link TaskManager} class.
*
* @param task The task.
*
* @return the {@link TaskManager} object.
*/
public TaskManager next(Task task)
{
if (null != task)
{
synchronized (mTaskList)
{
int id = mTaskList.size() + 1;
task.setTaskId(id);
mTaskList.add(task);
}
}
else
{
throw new NullPointerException("task is null");
}
return this;
}
/**
* Start to execute the tasks in the task manager.
*/
public void execute()
{
if (mTaskList.size() > 0)
{
startThread();
// Set the task to RUNNING.
setState(State.RUNNING);
// Perform the runnable in the handler which is associated to the background thread.
mThreadHandler.post(new Runnable()
{
@Override
public void run()
{
doInBackground();
}
});
}
else
{
quitLooper();
}
}
/**
* Start to execute the tasks in the task manager with the specified parameter.
*
* @param operation The task operation contains the task parameter.
*/
public void execute(TaskOperation operation)
{
if (null != operation)
{
mTaskOperation = operation;
}
execute();
}
/**
* Post execute a task which will be running in UI thread.
*
* @param task the task to be running.
*/
public void postExecute(Task task)
{
if (null == task)
{
throw new NullPointerException("Task can NOT be null.");
}
final Task runTask = task;
// If the task running status is UI_THREAD.
if (RunningStatus.UI_THREAD == runTask.getRunningStatus())
{
// The task is running in UI thread.
mUIHandler.post(new Runnable()
{
@Override
public void run()
{
executeTask(runTask);
}
});
}
}
/**
* Publish the task progress, if you call this method, the {@link Task#onProgressUpdate(Object)}
* method will be called, which is running in the UI thread.
*
* @param progresses The progress.
*/
public void publishProgress(Object progresses)
{
mUIHandler.obtainMessage(MESSAGE_POST_PROGRESS, progresses).sendToTarget();
}
/**
* Cancel the current running task.
*/
public void cancelCurrentTask()
{
if (null != mCurTask)
{
mCurTask.cancel();
}
}
/**
* Remove the tasks in the list.
*/
public void removeTasks()
{
synchronized (mTaskList)
{
if (mTaskList.size() > 0)
{
mTaskList.clear();
quitLooper();
}
}
}
/**
* Remove the specified task.
*
* @param task The task to be removed.
*/
public void removeTask(Task task)
{
synchronized (mTaskList)
{
mTaskList.remove(task);
if (mTaskList.isEmpty())
{
quitLooper();
}
}
}
/**
* Set the state change listener.
*
* @param listener
*/
public void setStateChangeListener(IStateChangeListener listener)
{
mListener = listener;
}
/**
* Get the task operation.
*
* @return
*/
public TaskOperation getTaskOperation()
{
return mTaskOperation;
}
/**
* @return the mName
*/
public String getName()
{
return mName;
}
/**
* Pause the worker thread.
*/
public void pause()
{
if (null != mThreadWorker)
{
setState(State.PAUSED);
mThreadWorker.pause();
}
}
/**
* Resume the worker thread from the waiting status.
*/
public void resume()
{
if (null != mThreadWorker)
{
setState(State.RUNNING);
mThreadWorker.restart();
}
}
/**
* Quit the looper so that the thread can finish correctly.
*/
public void quitLooper()
{
if (null != mThreadWorker)
{
mThreadWorker.quit();
mThreadWorker = null;
}
mThreadHandler = null;
// Set the task to FINISHED.
setState(State.FINISHED);
}
/**
* Blocks the current thread ({@link Thread#currentThread()}) until the receiver finishes its execution and dies.
*/
public final void join()
{
if (null != mThreadWorker)
{
mThreadWorker.join();
}
}
/**
* Get the task manager state.
*
* @return
*/
public State getState()
{
return mState;
}
/**
* Get the running task manager.
*
* @return HashMap<String, TaskManager>, the task manager's name is the key, and the
* task manager object is the value.
*/
public static HashMap<String, TaskManager> getTaskManagers()
{
return s_taskManagers;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Name = ").append(mName).append(" ");
sb.append("State = ").append(mState).append(" ");
sb.append(super.toString());
return sb.toString();
}
/**
* print task execute status
*
* @param task
*/
protected void printExecuteTaskState(Task task)
{
Log.d("TaskManager", " Executer the task: " + task.toString());
}
/**
* Set the state.
*
* @param state
*/
private void setState(State state)
{
final State oldState = mState;
final State newState = state;
mState = state;
if (mState == State.FINISHED)
{
popTaskManager(this);
}
else
{
pushTaskManager(this);
}
if (oldState != newState)
{
printTaskManagerState(oldState, newState);
performStateChange(oldState, newState);
}
}
/**
* Call this method to start the work thread if can.
*/
private void startThread()
{
if (null == mThreadWorker)
{
String name = TextUtils.isEmpty(mName) ? this.toString() : mName;
String threadName = "TaskManager_Thread_" + name;
mThreadWorker = new ThreadWorker(threadName);
mThreadHandler = new Handler(mThreadWorker.getLooper());
}
}
/**
* This method is running in the background thread.
*/
private void doInBackground()
{
mCurTask = null;
if (mTaskList.isEmpty())
{
return;
}
Task task = mTaskList.get(0);
mCurTask = task;
// Remove the first item in the list.
synchronized (mTaskList)
{
mTaskList.remove(0);
}
// If the task is allowed to be running in background thread, we execute the task
// now, the doInBackground() method is running in the background thread.
switch (task.getRunningStatus())
{
case WORK_THREAD:
executeTask(task);
// Try to run next task if possible.
runNextTask();
break;
case UI_THREAD:
// Send a message to the UI handler to executer the task.
mUIHandler.obtainMessage(MESSAGE_POST_EXECUTE, task).sendToTarget();
break;
}
}
/**
* Run the next task.
*/
private void runNextTask()
{
// If run next, call the execute() method again.
if (isRunNext())
{
execute();
}
}
/**
* Check whether run the next task if has one.
*
* @return true if run next task, otherwise false.
*/
private boolean isRunNext()
{
boolean isRunNext = true;
boolean hasNext = false;
if (null != mTaskOperation)
{
isRunNext = (mTaskOperation.getTaskManagerStatus() == TaskManagerState.CONTINUE);
}
if (null != mTaskList)
{
hasNext = mTaskList.size() > 0;
}
// No next task, quit the thread.
if (!hasNext)
{
quitLooper();
}
return (isRunNext && hasNext);
}
/**
* Execute the task, if will call {@link Task#onExecute(TaskOperation)} method.
*
* @param task The task object.
*/
private void executeTask(Task task)
{
if (null != task)
{
// Set the status of the task.
task.setStatus(Status.RUNNING);
// Print the task state.
this.printExecuteTaskState(task);
try
{
// Avoid the exception from task interrupting the task manager works.
mTaskOperation = task.onExecute(mTaskOperation);
}
catch (Exception e)
{
e.printStackTrace();
}
// Set the status of the task.
task.setStatus(Status.FINISHED);
// Print the task state.
this.printExecuteTaskState(task);
}
}
/**
* Post the progress, it will call {@link Task#onProgressUpdate(Object progresses)} method.
*
* @param progresses
*/
private void postProgress(Object progresses)
{
if (null != mCurTask)
{
mCurTask.onProgressUpdate(progresses);
}
}
/**
* Perform the state change.
*
* @param oldState
* @param newState
*/
private void performStateChange(final State oldState, final State newState)
{
if (null != mListener)
{
mUIHandler.post(new Runnable()
{
@Override
public void run()
{
mListener.onStateChanged(TaskManager.this, oldState, newState);
}
});
}
}
/**
* Print the task manager information.
*
* @param oldState
* @param newState
*/
private void printTaskManagerState(final State oldState, final State newState)
{
Log.d("TaskManager", "TaskManager state changed, task manager = " + this.toString());
}
/**
* Push the task manager to the list.
*
* @param taskManager
*/
private static void pushTaskManager(TaskManager taskManager)
{
if (null != taskManager)
{
String name = taskManager.getName();
if (!TextUtils.isEmpty(name))
{
s_taskManagers.put(name, taskManager);
}
}
}
/**
* Pop the task manager from the list.
* @param taskManager
*/
private static void popTaskManager(TaskManager taskManager)
{
if (null != taskManager)
{
String name = taskManager.getName();
s_taskManagers.remove(name);
}
}
}
/*
* System: CoreLib
* @version 1.00
*
* Copyright (C) 2010, LiHong.
*
*/
package com.nj1s.lib.task;
import java.util.HashMap;
import java.util.LinkedList;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.nj1s.lib.task.Task.RunningStatus;
import com.nj1s.lib.task.Task.Status;
import com.nj1s.lib.thread.ThreadWorker;
/**
* This class is used to manager the tasks so that you can add many tasks into the task manger
* and these tasks will be running one by one.
*
* <h2>Example:</h2>
* <pre class="prettyprint">
* private void showProgressDialog()
* {
* final ProgressDialog mProgressDialog = null;
* final TaskManager taskManager = new TaskManager("ShowProgressDlg");
*
* // Set the state change listener.
* taskManager.setStateChangeListener(new IStateChangeListener()
* {
* public void onStateChanged(TaskManager taskManager, State oldState, State newState)
* {
* Toast.makeText(ShowProgressDlgActivity.this, " onStateChanged state = " + newState, Toast.LENGTH_SHORT).show();
* }
* });
*
* taskManager
* .next(new Task(Task.RunningStatus.UI_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* mProgressDialog = new ProgressDialog(ShowProgressDlgActivity.this);
* mProgressDialog.setTitle("Download");
* mProgressDialog.setMessage("Downlonding data from server...");
* mProgressDialog.setCancelable(false);
* mProgressDialog.show();
*
* return null;
* }
* })
* .next(new Task(Task.RunningStatus.WORK_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* // Simulate the work thread.
* sleep(5000);
*
* return null;
* }
* })
* .next(new Task(Task.RunningStatus.UI_THREAD)
* {
* public TaskOperation onExecute(TaskOperation operation)
* {
* if (null != mProgressDialog && mProgressDialog.isShowing())
* {
* mProgressDialog.dismiss();
* mProgressDialog = null;
* }
*
* return null;
* }
* })
* .execute(); // Call this method to execute these tasks.
* }
* </pre>
*
* <h2>Note:</h2>
* <pre>
* The {@link Task} class must be specified the task running state, one of the enum {@link Task#RunningStatus}.
* </pre>
*
* @author LeeHong
*
* @date 2012/10/30
*
* @see {@link Task}
* @see {@link TaskOperation}
*/
public class TaskManager
{
/**
* Execute task message.
*/
private static final int MESSAGE_POST_EXECUTE = 0x01;
/**
* Update progress message.
*/
private static final int MESSAGE_POST_PROGRESS = 0x02;
/**
* The state change listener.
*/
public interface IStateChangeListener
{
/**
* Called when the task manager's state is changed. This method will be called in
* UI thread.
*
* @param taskManager Which task manager's state changed.
* @param oldState The old state.
* @param newState The new state.
*/
public void onStateChanged(TaskManager taskManager, State oldState, State newState);
}
/**
* A representation of a task manager's state. A given thread may only be in one
* state at a time.
*/
public enum State
{
/**
* The task manager has been created, but has never been started.
*/
NEW,
/**
* Indicate the task manager is running one task.
*/
RUNNING,
/**
* Indicate the task manager is paused, typically call {@link #pause()} method.
*/
PAUSED,
/**
* All tasks are finished.
*/
FINISHED,
}
/**
* The status of the {@link TaskManager} class.
*/
public enum TaskManagerState
{
/**
* Continue the task manager to run next task.
*/
CONTINUE,
/**
* Indicate the task manager pause to run next task.
*/
PAUSE,
}
/**
* The running task manager collection.
*/
private static HashMap<String, TaskManager> s_taskManagers = new HashMap<String, TaskManager>();
/**
* The task list.
*/
private LinkedList<Task> mTaskList = new LinkedList<Task>();
/**
* The task operation, it will pass from first task to the last task.
*/
private TaskOperation mTaskOperation = new TaskOperation();
/**
* The running thread worker, it own a looper which will be alive until you call
* {@link ThreadWorker#quit()} method.
*/
private ThreadWorker mThreadWorker = null;
/**
* The current perform task, may be null.
*/
private Task mCurTask = null;
/**
* The state of the task manager.
*/
private State mState = State.NEW;
/**
* The name of the task manager.
*/
private String mName = null;
/**
* The listener.
*/
private IStateChangeListener mListener = null;
/**
* The background thread handler, which is associated to a background thread looper.
*/
private Handler mThreadHandler = null;
/**
* The UI thread handler.
*/
private Handler mUIHandler = new Handler(Looper.getMainLooper())
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MESSAGE_POST_EXECUTE:
Task task = (Task)msg.obj;
executeTask(task);
// Try to run next task if possible.
runNextTask();
break;
case MESSAGE_POST_PROGRESS:
postProgress(msg.obj);
break;
}
}
};
/**
* The constructor method.
*/
public TaskManager()
{
}
/**
* The constructor method.
*
* @param name The name of the task manager.
*/
public TaskManager(String name)
{
mName = name;
}
/**
* Add the task to {@link TaskManager} class.
*
* @param task The task.
*
* @return the {@link TaskManager} object.
*/
public TaskManager next(Task task)
{
if (null != task)
{
synchronized (mTaskList)
{
int id = mTaskList.size() + 1;
task.setTaskId(id);
mTaskList.add(task);
}
}
else
{
throw new NullPointerException("task is null");
}
return this;
}
/**
* Start to execute the tasks in the task manager.
*/
public void execute()
{
if (mTaskList.size() > 0)
{
startThread();
// Set the task to RUNNING.
setState(State.RUNNING);
// Perform the runnable in the handler which is associated to the background thread.
mThreadHandler.post(new Runnable()
{
@Override
public void run()
{
doInBackground();
}
});
}
else
{
quitLooper();
}
}
/**
* Start to execute the tasks in the task manager with the specified parameter.
*
* @param operation The task operation contains the task parameter.
*/
public void execute(TaskOperation operation)
{
if (null != operation)
{
mTaskOperation = operation;
}
execute();
}
/**
* Post execute a task which will be running in UI thread.
*
* @param task the task to be running.
*/
public void postExecute(Task task)
{
if (null == task)
{
throw new NullPointerException("Task can NOT be null.");
}
final Task runTask = task;
// If the task running status is UI_THREAD.
if (RunningStatus.UI_THREAD == runTask.getRunningStatus())
{
// The task is running in UI thread.
mUIHandler.post(new Runnable()
{
@Override
public void run()
{
executeTask(runTask);
}
});
}
}
/**
* Publish the task progress, if you call this method, the {@link Task#onProgressUpdate(Object)}
* method will be called, which is running in the UI thread.
*
* @param progresses The progress.
*/
public void publishProgress(Object progresses)
{
mUIHandler.obtainMessage(MESSAGE_POST_PROGRESS, progresses).sendToTarget();
}
/**
* Cancel the current running task.
*/
public void cancelCurrentTask()
{
if (null != mCurTask)
{
mCurTask.cancel();
}
}
/**
* Remove the tasks in the list.
*/
public void removeTasks()
{
synchronized (mTaskList)
{
if (mTaskList.size() > 0)
{
mTaskList.clear();
quitLooper();
}
}
}
/**
* Remove the specified task.
*
* @param task The task to be removed.
*/
public void removeTask(Task task)
{
synchronized (mTaskList)
{
mTaskList.remove(task);
if (mTaskList.isEmpty())
{
quitLooper();
}
}
}
/**
* Set the state change listener.
*
* @param listener
*/
public void setStateChangeListener(IStateChangeListener listener)
{
mListener = listener;
}
/**
* Get the task operation.
*
* @return
*/
public TaskOperation getTaskOperation()
{
return mTaskOperation;
}
/**
* @return the mName
*/
public String getName()
{
return mName;
}
/**
* Pause the worker thread.
*/
public void pause()
{
if (null != mThreadWorker)
{
setState(State.PAUSED);
mThreadWorker.pause();
}
}
/**
* Resume the worker thread from the waiting status.
*/
public void resume()
{
if (null != mThreadWorker)
{
setState(State.RUNNING);
mThreadWorker.restart();
}
}
/**
* Quit the looper so that the thread can finish correctly.
*/
public void quitLooper()
{
if (null != mThreadWorker)
{
mThreadWorker.quit();
mThreadWorker = null;
}
mThreadHandler = null;
// Set the task to FINISHED.
setState(State.FINISHED);
}
/**
* Blocks the current thread ({@link Thread#currentThread()}) until the receiver finishes its execution and dies.
*/
public final void join()
{
if (null != mThreadWorker)
{
mThreadWorker.join();
}
}
/**
* Get the task manager state.
*
* @return
*/
public State getState()
{
return mState;
}
/**
* Get the running task manager.
*
* @return HashMap<String, TaskManager>, the task manager's name is the key, and the
* task manager object is the value.
*/
public static HashMap<String, TaskManager> getTaskManagers()
{
return s_taskManagers;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Name = ").append(mName).append(" ");
sb.append("State = ").append(mState).append(" ");
sb.append(super.toString());
return sb.toString();
}
/**
* print task execute status
*
* @param task
*/
protected void printExecuteTaskState(Task task)
{
Log.d("TaskManager", " Executer the task: " + task.toString());
}
/**
* Set the state.
*
* @param state
*/
private void setState(State state)
{
final State oldState = mState;
final State newState = state;
mState = state;
if (mState == State.FINISHED)
{
popTaskManager(this);
}
else
{
pushTaskManager(this);
}
if (oldState != newState)
{
printTaskManagerState(oldState, newState);
performStateChange(oldState, newState);
}
}
/**
* Call this method to start the work thread if can.
*/
private void startThread()
{
if (null == mThreadWorker)
{
String name = TextUtils.isEmpty(mName) ? this.toString() : mName;
String threadName = "TaskManager_Thread_" + name;
mThreadWorker = new ThreadWorker(threadName);
mThreadHandler = new Handler(mThreadWorker.getLooper());
}
}
/**
* This method is running in the background thread.
*/
private void doInBackground()
{
mCurTask = null;
if (mTaskList.isEmpty())
{
return;
}
Task task = mTaskList.get(0);
mCurTask = task;
// Remove the first item in the list.
synchronized (mTaskList)
{
mTaskList.remove(0);
}
// If the task is allowed to be running in background thread, we execute the task
// now, the doInBackground() method is running in the background thread.
switch (task.getRunningStatus())
{
case WORK_THREAD:
executeTask(task);
// Try to run next task if possible.
runNextTask();
break;
case UI_THREAD:
// Send a message to the UI handler to executer the task.
mUIHandler.obtainMessage(MESSAGE_POST_EXECUTE, task).sendToTarget();
break;
}
}
/**
* Run the next task.
*/
private void runNextTask()
{
// If run next, call the execute() method again.
if (isRunNext())
{
execute();
}
}
/**
* Check whether run the next task if has one.
*
* @return true if run next task, otherwise false.
*/
private boolean isRunNext()
{
boolean isRunNext = true;
boolean hasNext = false;
if (null != mTaskOperation)
{
isRunNext = (mTaskOperation.getTaskManagerStatus() == TaskManagerState.CONTINUE);
}
if (null != mTaskList)
{
hasNext = mTaskList.size() > 0;
}
// No next task, quit the thread.
if (!hasNext)
{
quitLooper();
}
return (isRunNext && hasNext);
}
/**
* Execute the task, if will call {@link Task#onExecute(TaskOperation)} method.
*
* @param task The task object.
*/
private void executeTask(Task task)
{
if (null != task)
{
// Set the status of the task.
task.setStatus(Status.RUNNING);
// Print the task state.
this.printExecuteTaskState(task);
try
{
// Avoid the exception from task interrupting the task manager works.
mTaskOperation = task.onExecute(mTaskOperation);
}
catch (Exception e)
{
e.printStackTrace();
}
// Set the status of the task.
task.setStatus(Status.FINISHED);
// Print the task state.
this.printExecuteTaskState(task);
}
}
/**
* Post the progress, it will call {@link Task#onProgressUpdate(Object progresses)} method.
*
* @param progresses
*/
private void postProgress(Object progresses)
{
if (null != mCurTask)
{
mCurTask.onProgressUpdate(progresses);
}
}
/**
* Perform the state change.
*
* @param oldState
* @param newState
*/
private void performStateChange(final State oldState, final State newState)
{
if (null != mListener)
{
mUIHandler.post(new Runnable()
{
@Override
public void run()
{
mListener.onStateChanged(TaskManager.this, oldState, newState);
}
});
}
}
/**
* Print the task manager information.
*
* @param oldState
* @param newState
*/
private void printTaskManagerState(final State oldState, final State newState)
{
Log.d("TaskManager", "TaskManager state changed, task manager = " + this.toString());
}
/**
* Push the task manager to the list.
*
* @param taskManager
*/
private static void pushTaskManager(TaskManager taskManager)
{
if (null != taskManager)
{
String name = taskManager.getName();
if (!TextUtils.isEmpty(name))
{
s_taskManagers.put(name, taskManager);
}
}
}
/**
* Pop the task manager from the list.
* @param taskManager
*/
private static void popTaskManager(TaskManager taskManager)
{
if (null != taskManager)
{
String name = taskManager.getName();
s_taskManagers.remove(name);
}
}
}
本文實例講述了Android選項菜單用法。分享給大家供大家參考。具體如下:Android平台下所提供的菜單大體上可分為三類:選項菜單、上下文菜單和子菜單。當Activit
先給大家展示下效果圖,大家覺效果滿意,請參考實現代碼。直接上代碼:private void setDialog(){View view = getLayoutInflat
本文目的如下:1、加一個設置初始密碼的功能2、讓手勢單點生效3、讓繪制路徑的中間點自動加入軌跡(例如選中第一排的1位和3位時2位也能自動選中)4、一些其它方面的優化&nb
本文實例為大家分享了Android刮刮卡效果,供大家參考,具體內容如下android實現底層一張圖片,上層一個遮罩層,觸摸滑動按手指滑動路徑實現去除遮罩效果,類似於抽獎的