为了使UI在数据获取时不僵死,数据获取需要在新开Worker线程中进行,然后将返回结果在UI线程中进行读取并渲染页面。面对这种异步处理,到底如何写才简洁,先后面临过三种实现方式。
首先是最原始的Java方式,new 一个Thread出来,将处理Runnable进去执行,执行完之后通过handler post到ui线程去更新界面。然后发现1.5后有了AsyncTask,非常好用,以后的项目中全部改成衍生出一个AsyncTask的子类,类中自然定义了运行前方法、运行中方法和运行后在ui中运行的方法。目前我做的项目中对AsyncTask做了封装,把它从原本的子类编写的过程,改成了函数调用方式,这就是目前正使用的第三种方法。
一个Android应用中,Activity通常可以建立以上层次关系。然后,在BaseActivity中对AsyncTask进行了封装,形成doAsync方法。方法体内创建一个新的AsyncTask并执行,由于AsyncTask是泛型参数,doAsync方法中传入的接口的参数也对应使用了泛型。至此,一个典型的异步调用的案例如下:
this.doAsync(newCallable() {
// 希望异步加载的数据
publicString call()throwsException {
String resu = NetworkTool.httpGetURL(
"http://www.baidu.com","GBK");
returnresu;
}
},newCallback() {
// 当加载完成后回调,在UI线程中的操作
publicvoidonCallback(finalString resu) {
if(null!= resu) {
tv_text1.setText(getRT().text1 + resu);
}else{
Tools.ShowNetErr(HomeActivity.this);
}
}
});
这样,就从本来继承AsyncTask创建一个子类,然后初始化,然后运行的开发过程转变为了函数调用的过程。可以看到,调用可是简洁了很多!
为了实现它,我们附上BaseActivity中如下封装代码,需要说明的是这不是我的原创,我借鉴于Andengine引擎的实现代码进行的修改。
附源码:
publicclassActivityUtils {
publicstaticvoiddoAsync(finalContext pContext,finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback) {
ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback,null,false);
}
publicstaticvoiddoAsync(finalContext pContext,finalCharSequence pTitle,finalCharSequence pMessage,finalCallable pCallable,finalCallback pCallback) {
ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback,null,false);
}
publicstaticvoiddoAsync(finalContext pContext,finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback,finalbooleanpCancelable) {
ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback,null, pCancelable);
}
publicstaticvoiddoAsync(finalContext pContext,finalCharSequence pTitle,finalCharSequence pMessage,finalCallable pCallable,finalCallback pCallback,finalbooleanpCancelable) {
ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback,null, pCancelable);
}
publicstaticvoiddoAsync(finalContext pContext,finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback, pExceptionCallback,false);
}
publicstaticvoiddoAsync(finalContext pContext,finalCharSequence pTitle,finalCharSequence pMessage,finalCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback, pExceptionCallback,false);
}
publicstaticvoiddoAsync(finalContext pContext,finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback,finalbooleanpCancelable) {
ActivityUtils.doAsync(pContext, pContext.getString(pTitleResID), pContext.getString(pMessageResID), pCallable, pCallback, pExceptionCallback, pCancelable);
}
publicstaticvoiddoAsync(finalContext pContext,finalCharSequence pTitle,finalCharSequence pMessage,finalCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback,finalbooleanpCancelable) {
newAsyncTask() {
privateProgressDialog mPD;
privateException mException =null;
@Override
publicvoidonPreExecute() {
this.mPD = ProgressDialog.show(pContext, pTitle, pMessage,true, pCancelable);
if(pCancelable) {
this.mPD.setOnCancelListener(newOnCancelListener() {
@Override
publicvoidonCancel(finalDialogInterface pDialogInterface) {
pExceptionCallback.onCallback(newCancelledException());
pDialogInterface.dismiss();
}
});
}
super.onPreExecute();
}
@Override
publicT doInBackground(finalVoid... params) {
try{
returnpCallable.call();
}catch(finalException e) {
this.mException = e;
}
returnnull;
}
@Override
publicvoidonPostExecute(finalT result) {
try{
this.mPD.dismiss();
}catch(finalException e) {
Log.e("Error", e.toString());
}
if(this.isCancelled()) {
this.mException =newCancelledException();
}
if(this.mException ==null) {
pCallback.onCallback(result);
}else{
if(pExceptionCallback ==null) {
if(this.mException !=null)
Log.e("Error",this.mException.toString());
}else{
pExceptionCallback.onCallback(this.mException);
}
}
super.onPostExecute(result);
}
}.execute((Void[])null);
}
publicstaticvoiddoProgressAsync(finalContext pContext,finalintpTitleResID,finalProgressCallable pCallable,finalCallback pCallback) {
ActivityUtils.doProgressAsync(pContext, pTitleResID, pCallable, pCallback,null);
}
publicstaticvoiddoProgressAsync(finalContext pContext,finalintpTitleResID,finalProgressCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
newAsyncTask() {
privateProgressDialog mPD;
privateException mException =null;
@Override
publicvoidonPreExecute() {
this.mPD =newProgressDialog(pContext);
this.mPD.setTitle(pTitleResID);
this.mPD.setIcon(android.R.drawable.ic_menu_save);
this.mPD.setIndeterminate(false);
this.mPD.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
this.mPD.show();
super.onPreExecute();
}
@Override
publicT doInBackground(finalVoid... params) {
try{
returnpCallable.call(newIProgressListener() {
@Override
publicvoidonProgressChanged(finalintpProgress) {
onProgressUpdate(pProgress);
}
});
}catch(finalException e) {
this.mException = e;
}
returnnull;
}
@Override
publicvoidonProgressUpdate(finalInteger... values) {
this.mPD.setProgress(values[0]);
}
@Override
publicvoidonPostExecute(finalT result) {
try{
this.mPD.dismiss();
}catch(finalException e) {
Log.e("Error", e.getLocalizedMessage());
/* Nothing. */
}
if(this.isCancelled()) {
this.mException =newCancelledException();
}
if(this.mException ==null) {
pCallback.onCallback(result);
}else{
if(pExceptionCallback ==null) {
Log.e("Error",this.mException.getLocalizedMessage());
}else{
pExceptionCallback.onCallback(this.mException);
}
}
super.onPostExecute(result);
}
}.execute((Void[])null);
}
publicstaticvoiddoAsync(finalContext pContext,finalintpTitleResID,finalintpMessageResID,finalAsyncCallable pAsyncCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
finalProgressDialog pd = ProgressDialog.show(pContext, pContext.getString(pTitleResID), pContext.getString(pMessageResID));
pAsyncCallable.call(newCallback() {
@Override
publicvoidonCallback(finalT result) {
try{
pd.dismiss();
}catch(finalException e) {
Log.e("Error", e.getLocalizedMessage());
/* Nothing. */
}
pCallback.onCallback(result);
}
}, pExceptionCallback);
}
publicstaticclassCancelledExceptionextendsException {
privatestaticfinallongserialVersionUID = -78123211381435595L;
}
}
publicinterfaceAsyncCallable {
// ===========================================================
// Final Fields
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
/**
* Computes a result asynchronously, return values and exceptions are to be handled through the callbacks.
* This method is expected to return almost immediately, after starting a {@link Thread} or similar.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
publicvoidcall(finalCallback pCallback,finalCallback pExceptionCallback);
}
publicinterfaceCallback {
// ===========================================================
// Final Fields
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
/**
* 当加载完成后回调,加载完毕的事后处理
*/
publicvoidonCallback(finalT pCallbackValue);
}
publicinterfaceIProgressListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
/**
* @param pProgress between 0 and 100.
*/
publicvoidonProgressChanged(finalintpProgress);
}
publicinterfaceIProgressListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
/**
* @param pProgress between 0 and 100.
*/
publicvoidonProgressChanged(finalintpProgress);
}
publicclassBaseActivityextendsActivity {
/**
*
* @param 模板参数,操作时要返回的内容
* @param pCallable 需要异步调用的操作
* @param pCallback 回调
*/
protectedvoiddoAsync(finalCallable pCallable,finalCallback pCallback) {
ActivityUtils.doAsync(this,null,"内容读取中,请稍等...", pCallable, pCallback,null,false);
}
protectedvoiddoAsync(finalCharSequence pTitle,finalCharSequence pMessage,finalCallable pCallable,finalCallback pCallback) {
ActivityUtils.doAsync(this, pTitle, pMessage, pCallable, pCallback,null,false);
}
/**
* Performs a task in the background, showing a {@link ProgressDialog},
* while the {@link Callable} is being processed.
*
* @param
* @param pTitleResID
* @param pMessageResID
* @param pErrorMessageResID
* @param pCallable
* @param pCallback
*/
protectedvoiddoAsync(finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback) {
this.doAsync(pTitleResID, pMessageResID, pCallable, pCallback,null);
}
/**
* Performs a task in the background, showing a indeterminate {@link ProgressDialog},
* while the {@link Callable} is being processed.
*
* @param
* @param pTitleResID
* @param pMessageResID
* @param pErrorMessageResID
* @param pCallable
* @param pCallback
* @param pExceptionCallback
*/
protectedvoiddoAsync(finalintpTitleResID,finalintpMessageResID,finalCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
ActivityUtils.doAsync(this, pTitleResID, pMessageResID, pCallable, pCallback, pExceptionCallback);
}
/**
* Performs a task in the background, showing a {@link ProgressDialog} with an ProgressBar,
* while the {@link AsyncCallable} is being processed.
*
* @param
* @param pTitleResID
* @param pMessageResID
* @param pErrorMessageResID
* @param pAsyncCallable
* @param pCallback
*/
protectedvoiddoProgressAsync(finalintpTitleResID,finalProgressCallable pCallable,finalCallback pCallback) {
this.doProgressAsync(pTitleResID, pCallable, pCallback,null);
}
/**
* Performs a task in the background, showing a {@link ProgressDialog} with a ProgressBar,
* while the {@link AsyncCallable} is being processed.
*
* @param
* @param pTitleResID
* @param pMessageResID
* @param pErrorMessageResID
* @param pAsyncCallable
* @param pCallback
* @param pExceptionCallback
*/
protectedvoiddoProgressAsync(finalintpTitleResID,finalProgressCallable pCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
ActivityUtils.doProgressAsync(this, pTitleResID, pCallable, pCallback, pExceptionCallback);
}
/**
* Performs a task in the background, showing an indeterminate {@link ProgressDialog},
* while the {@link AsyncCallable} is being processed.
*
* @param
* @param pTitleResID
* @param pMessageResID
* @param pErrorMessageResID
* @param pAsyncCallable
* @param pCallback
* @param pExceptionCallback
*/
protectedvoiddoAsync(finalintpTitleResID,finalintpMessageResID,finalAsyncCallable pAsyncCallable,finalCallback pCallback,finalCallback pExceptionCallback) {
ActivityUtils.doAsync(this, pTitleResID, pMessageResID, pAsyncCallable, pCallback, pExceptionCallback);
}
}