Android 中UI與耗時操作的分離
做過Android手機開發的人都知道,手機UI是一個單獨的線程在運行,并且該線程最好不會因為用戶的操作而阻塞。換句話說,如果用戶進行的操作需要耗時幾十秒甚至幾十分鐘,那么在這段時間內占用UI線程是一個非常不明智的做法。它會阻塞掉UI線程,導致手機不再顯示或者接受用戶新的操作,給用戶一種死機的感覺。
因此最好的方法是將用戶耗時較長的操作放到另一個線程中去,并且用監聽者模式來監聽操作的完成。比如,手機服務通過http協議與服務器建立通訊,為了使此通訊不會阻塞手機其他功能的顯示,需要開辟一個新線程傳輸數據,一旦數據傳輸完畢,則會調用監聽者的回調函數,將結果顯示在手機屏幕上。本文將介紹一種UI和耗時操作分離的方法:
每個復雜操作我們需要將其抽象成一個Task:
//定義一個BaseTask基類,其中taskParameter是需要執行任務所要傳遞的參數
//而execute()函數將在派生類中被重寫
public abstract class BaseTask { Object taskParameter;
abstract Object execute() throws Exception;
}在基類基礎上,定義派生類:public class AsynMethodTask extends BaseTask {
public AsynMethodTask(AsynMethodTaskParameter taskParameter) {
this.taskParameter = taskParameter;
}
//重寫execute函數,這里利用了Java提供的Method類,instance是需要執行的類,而methodName是需要執行的方法,methodParameter是需要傳遞的參數
@Override
public Object execute() throws Exception {
AsynMethodTaskParameter parameters = (AsynMethodTaskParameter) this.taskParameter;
Method method = MethodHelper.getMethod(parameters.instance,
parameters.methodName, parameters.methodParameters);
if (method != null) {
return method.invoke(parameters.instance,
parameters.methodParameters);
}
return null;
}
//工廠模式,返回一個Task的實例
public static AsynMethodTask CreateTask(Object instance, String methodName,
Object... parameters) {
return new AsynMethodTask(new AsynMethodTaskParameter(instance,
methodName, parameters));
}
}
AsynMethodTaskParameter定義如下:
public class AsynMethodTaskParameter{
public Object instance;
public String methodName;
public Object[] methodParameters;
public AsynMethodTaskParameter (Object instance , String methodName,Object[] methodParameters )
{
this.instance = instance;
this.methodName = methodName;
this.methodParameters = methodParameters;
}
}
這樣,一個基本的TASK方法已經實現,那么如何使用它呢?我們需要一個Request類來發送請求,并且異步啟用task:
public class Request extends AsyncTask<RequestParameter, Integer, Object> {
private RequestListener emmaRequestListener = null;
private Object data = null;
private Exception _errorException = null;
//在后臺異步啟動TASK,AsyncTask提供了異步功能,需要重載其中的回調函數
@Override
protected Object doInBackground(RequestParameter... parameter) {
try {
RequestParameter emmaRequestParameter = parameter[0];
emmaRequestListener = emmaRequestParameter.requestListener;
data = emmaRequestParameter.data;
BaseTask task = emmaRequestParameter.task;
return task.execute();
}
catch (InvocationTargetException e) {
Throwable baseException = e.getCause() ;
if (baseException == null)
_errorException = new LocalGeneralException(e.getMessage());
else {
if (baseException instanceof ServerGeneralException)
{
_errorException = new ServerGeneralException(baseException.getMessage());
}
else if (baseException instanceof ServerAuthException)
{
_errorException = new ServerAuthException(baseException.getMessage());
}
else {
_errorException = new LocalGeneralException(baseException.getMessage());
}
}
}
catch (Exception e) {
_errorException = new LocalGeneralException(e.getMessage());
}
return _errorException;
}
//執行結束后,如果沒有異常,則調用回調函數
@Override
protected void onPostExecute(Object result) {
if (_errorException == null) {
emmaRequestListener.onRequestSuccess(result, data);
} else {
emmaRequestListener.onRequestFailed(_errorException, data);
}
}
//中途如果被cancel掉
@Override
protected void onCancelled() {
emmaRequestListener.onRequestCanceled(data);
}
public interface RequestListener {
void onRequestSuccess(Object result, Object data);
void onRequestFailed(Object result, Object data);
// void onRequestCanceled(Object data);
}
//定義執行過程,需要加入task,如果成功會調用RequestListener所定義的函數
public static Request executeAsynRequest(BaseTask task,
RequestListener requestListener, Object data) {
RequestParameter requestParameter = new RequestParameter(task,
requestListener, data);
Request r = new Request();
r.execute(requestParameter);
return r;
}
}
最后我們只需要定義好Method的名字:
public final static class Methods
{
public static String getProfileView = "getProfileView";
public static String uploadProfileView = "uploadProfileView";
public static String getUserProfile = "getUserProfile";
}
就可以正常調用了:
AsynMethodTask task = AsynMethodTask.CreateTask(profileModel, ProfileModel.Methods.uploadProfileView, profileUploadData); Request.executeAsynRequest(task, this, TASK_UPLOAD_PROFILE);
整個過程相當簡單,最重要的是熟悉觀察者模式,以及AsyncTask類的運行方式,重載其中的回調函數,讓我們的任務在后臺運行。返回的值為Object對象,需要通過強制類型轉換成為我們需要的值。而傳遞進去的參數可以通過無限制數目的參數傳遞。
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!