為了使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(new callable<string>() {
// 希望異步加載的資料
public string call() throws exception {
string resu = networktool.httpgeturl(
"http://www.baidu.com", "gbk");
return resu;
}
}, new callback<string>() {
// 當加載完成後回調,在ui線程中的操作
public void oncallback(final string resu) {
if (null != resu) {
tv_text1.settext(getrt().text1 + resu);
} else {
tools.showneterr(homeactivity.this);
}
});
這樣,就從本來繼承asynctask建立一個子類,然後初始化,然後運作的開發過程轉變為了函數調用的過程。可以看到,調用可是簡潔了很多!
為了實作它,我們附上baseactivity中如下封裝代碼,需要說明的是這不是我的原創,我借鑒于andengine引擎的實作代碼進行的修改。
附源碼:
public class activityutils {
public static <t> void doasync(final context pcontext, final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback) {
activityutils.doasync(pcontext, ptitleresid, pmessageresid, pcallable, pcallback, null, false);
}
public static <t> void doasync(final context pcontext, final charsequence ptitle, final charsequence pmessage, final callable<t> pcallable, final callback<t> pcallback) {
activityutils.doasync(pcontext, ptitle, pmessage, pcallable, pcallback, null, false);
public static <t> void doasync(final context pcontext, final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback, final boolean pcancelable) {
activityutils.doasync(pcontext, ptitleresid, pmessageresid, pcallable, pcallback, null, pcancelable);
public static <t> void doasync(final context pcontext, final charsequence ptitle, final charsequence pmessage, final callable<t> pcallable, final callback<t> pcallback, final boolean pcancelable) {
activityutils.doasync(pcontext, ptitle, pmessage, pcallable, pcallback, null, pcancelable);
public static <t> void doasync(final context pcontext, final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
activityutils.doasync(pcontext, ptitleresid, pmessageresid, pcallable, pcallback, pexceptioncallback, false);
public static <t> void doasync(final context pcontext, final charsequence ptitle, final charsequence pmessage, final callable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
activityutils.doasync(pcontext, ptitle, pmessage, pcallable, pcallback, pexceptioncallback, false);
public static <t> void doasync(final context pcontext, final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback, final boolean pcancelable) {
activityutils.doasync(pcontext, pcontext.getstring(ptitleresid), pcontext.getstring(pmessageresid), pcallable, pcallback, pexceptioncallback, pcancelable);
public static <t> void doasync(final context pcontext, final charsequence ptitle, final charsequence pmessage, final callable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback, final boolean pcancelable) {
new asynctask<void, void, t>() {
private progressdialog mpd;
private exception mexception = null;
@override
public void onpreexecute() {
this.mpd = progressdialog.show(pcontext, ptitle, pmessage, true, pcancelable);
if(pcancelable) {
this.mpd.setoncancellistener(new oncancellistener() {
@override
public void oncancel(final dialoginterface pdialoginterface) {
pexceptioncallback.oncallback(new cancelledexception());
pdialoginterface.dismiss();
}
});
super.onpreexecute();
public t doinbackground(final void... params) {
try {
return pcallable.call();
} catch (final exception e) {
this.mexception = e;
return null;
public void onpostexecute(final t result) {
this.mpd.dismiss();
log.e("error", e.tostring());
if(this.iscancelled()) {
this.mexception = new cancelledexception();
if(this.mexception == null) {
pcallback.oncallback(result);
if(pexceptioncallback == null) {
if (this.mexception != null)
log.e("error", this.mexception.tostring());
} else {
pexceptioncallback.oncallback(this.mexception);
}
super.onpostexecute(result);
}.execute((void[]) null);
public static <t> void doprogressasync(final context pcontext, final int ptitleresid, final progresscallable<t> pcallable, final callback<t> pcallback) {
activityutils.doprogressasync(pcontext, ptitleresid, pcallable, pcallback, null);
public static <t> void doprogressasync(final context pcontext, final int ptitleresid, final progresscallable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
new asynctask<void, integer, t>() {
this.mpd = new progressdialog(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();
return pcallable.call(new iprogresslistener() {
public void onprogresschanged(final int pprogress) {
onprogressupdate(pprogress);
public void onprogressupdate(final integer... values) {
this.mpd.setprogress(values[0]);
log.e("error", e.getlocalizedmessage());
/* nothing. */
log.e("error", this.mexception.getlocalizedmessage());
public static <t> void doasync(final context pcontext, final int ptitleresid, final int pmessageresid, final asynccallable<t> pasynccallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
final progressdialog pd = progressdialog.show(pcontext, pcontext.getstring(ptitleresid), pcontext.getstring(pmessageresid));
pasynccallable.call(new callback<t>() {
public void oncallback(final t result) {
pd.dismiss();
pcallback.oncallback(result);
}, pexceptioncallback);
public static class cancelledexception extends exception {
private static final long serialversionuid = -78123211381435595l;
}
public interface asynccallable<t> {
// ===========================================================
// 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
*/
public void call(final callback<t> pcallback, final callback<exception> pexceptioncallback);
public interface callback<t> {
* 當加載完成後回調,加載完畢的事後處理
public void oncallback(final t pcallbackvalue);
public interface iprogresslistener {
// constants
* @param pprogress between 0 and 100.
public void onprogresschanged(final int pprogress);
public class baseactivity extends activity {
*
* @param <t> 模闆參數,操作時要傳回的内容
* @param pcallable 需要異步調用的操作
* @param pcallback 回調
protected <t> void doasync(final callable<t> pcallable, final callback<t> pcallback) {
activityutils.doasync(this, null, "内容讀取中,請稍等...", pcallable, pcallback, null, false);
protected <t> void doasync(final charsequence ptitle, final charsequence pmessage, final callable<t> pcallable, final callback<t> 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 <t>
* @param ptitleresid
* @param pmessageresid
* @param perrormessageresid
* @param pcallable
* @param pcallback
protected <t> void doasync(final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback) {
this.doasync(ptitleresid, pmessageresid, pcallable, pcallback, null);
* performs a task in the background, showing a indeterminate {@link progressdialog},
* @param pexceptioncallback
protected <t> void doasync(final int ptitleresid, final int pmessageresid, final callable<t> pcallable, final callback<t> pcallback, final callback<exception> 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 pasynccallable
protected <t> void doprogressasync(final int ptitleresid, final progresscallable<t> pcallable, final callback<t> pcallback) {
this.doprogressasync(ptitleresid, pcallable, pcallback, null);
* performs a task in the background, showing a {@link progressdialog} with a progressbar,
protected <t> void doprogressasync(final int ptitleresid, final progresscallable<t> pcallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
activityutils.doprogressasync(this, ptitleresid, pcallable, pcallback, pexceptioncallback);
* performs a task in the background, showing an indeterminate {@link progressdialog},
protected <t> void doasync(final int ptitleresid, final int pmessageresid, final asynccallable<t> pasynccallable, final callback<t> pcallback, final callback<exception> pexceptioncallback) {
activityutils.doasync(this, ptitleresid, pmessageresid, pasynccallable, pcallback, pexceptioncallback);
}