5

我在我的項目中有幾個Activity子類,每個都調用基於SOAP的Web服務,處理並顯示結果。 SOAP序列化,呼叫處理以及將結果解析爲各種POJO對象都封裝在MyWebService類中。該類通過AsyncTask執行實際的Web服務調用。通過多個活動重複使用Android AsnycTask的模式?

爲了能夠將結果傳回給調用的Activity子類,我想我強制所有這些活動都應該實現一個WebServiceResultProcessor接口,定義一個函數(processWebServiceResults)充當AsyncTask的回調函數,從onPostExecute 。

我還希望在Web服務調用期間顯示ProgressDialog。我的問題來了。爲了能夠顯示ProgressDialog(來自MyWebService或它的AsyncTask),我需要傳遞對調用者Activity的上下文的引用。並且爲了能夠從AsyncTask執行回調函數,我還需要傳遞相同的對象引用,但這次是作爲WebServiceResultProcessor。這對我來說似乎是一種代碼味道,兩次傳遞同一個對象,但是看不到任何方式。除了接口之外,我可以創建一個新的基類,擴展Activity類並從擴展類強制繼承,但這意味着我會使用此MyWebService類來排除ListActivity和類似內容。

有沒有更好的方法來做到這一點?

+0

請問您WebServiceResultProcessor擴展上下文/活動? –

+0

@HeikoRupp不,我可能會更喜歡這樣。 –

回答

0

儘管Arhimed的警告,我結束了使用AsyncTask,因爲它仍然符合我的目的。我只是確保所有調用Web服務的活動在其onDestroy()上發送cancel()到被調用的AsyncTask。 AsyncTask實現本身通過在任何需要的地方檢查isCancelled()來優雅地處理取消請求。

至於原來的問題,我一定有過失 - 解決方案非常簡單。我將Activity子類實例作爲Object傳遞給AsyncTask,並根據需要將其轉換爲Context或WebServiceResultProcessor。片段展示它是如何工作:

if (callerActivity instanceof Context) { 
    ProgressDialog dialog = new ProgressDialog((Context)callerActivity); 
} 

...

if (callerActivity instanceof WebServiceResultProcessor) { 
    ((WebServiceResultProcessor)callerActivity).processWebServiceResults(soapObject); 
} 
+1

我覺得'if(callerActivity instanceof Context){..}'是一個多餘的檢查。除非我遺漏了任何東西''callerActivity'在你的案例中總是一個'Context'的實例,所以你可以直接調用進度創建代碼。 –

4

+1,一個很好的問題!

這不是你的問題的直接答案。但是讓我說,我認爲AsyncTask不是這樣的東西的正確選擇。我認爲是因爲在這種情況下,AsyncTask持有對Activity的引用(通過ProgressDialog實例或從onPostExecute()調用的回調)。

想象一下:在Android系統中,在AsyncTask執行其doInBackground()之前,操作系統可能會終止Activity。這當然是某種角落案件,但這並非不可能。考慮一個場景:用戶接到來電,你的活動變得不可見,操作系統需要更多的RAM,因此它決定殺死你的活動。內存泄漏的情況下,至少。

我不知道Google爲什麼隱瞞UI如何與後臺任務正確分離的信息。是的,他們說「使用服務」。但這不是一件小事。遺憾的是,Google幾乎爲每個開發主題都提供了很好的指導,但不是這一個。不過,我可以建議檢查「Google I/O 2010 - Android REST client applications」演示文稿以獲取靈感。看起來他們給出了一個關於如何在Android上完成這些事情的關鍵。

+0

感謝您在AsyncTask中指出使用Context引用的危險。我發現這個http://stackoverflow.com/questions/3357477/is-asynctask-really-conceptually-flawed-or-am-i-just-missing-some問題和答案涵蓋了這個話題相當廣泛。 –

+0

@AndrásSzepesházi:謝謝,這是一個很好的討論。但是,他們主要討論如何解決配置更改(例如,設備輪換時重新啓動活動)。但是如果在我描述的情況下(來電)活動被殺死,而在遠程服務器上創建新用戶帳戶的asynctask呢? :)帳戶將被創建,但是當用戶回到活動中時,它永遠不會知道這個asynctask的結果。因此,用戶將重試並獲得「此用戶名已被使用」的錯誤? :)好吧,如果asycntask做了付款交易呢? :) –

+0

哇,這是邪惡的。我很想避免使用服務和處理程序,但似乎這是唯一的出路。 –

3

您可以查看此博客文章(part 1part 2),該文章使用AsyncTaskLoader和具有Service組件的相同Web服務實現Web服務。此外,它還顯示了兩種方法之間的差異,並且文章中也有有趣的評論。