清單 3. 實(shí)際工作的多線程 — 通過(guò)使用 Handler
private void refreshStockData(){ final ArrayList<Stock> localStocks = new ArrayList<Stock>(stocks.size()); for (Stock stock : stocks){ localStocks.add(new Stock(stock, stock.getId())); } final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { for (int i=0;i<stocks.size();i++){ stocks.set(i, localStocks.get(i)); } refresh(); } }; Runnable task = new Runnable(){ public void run() { try { ArrayList<Stock> newStocks = fetchStockData(localStocks.toArray( new Stock[localStocks.size()])); for (int i=0;i<localStocks.size();i++){ Stock ns = newStocks.get(i); Stock ls = localStocks.get(i); ls.setName(ns.getName()); ls.setCurrentPrice(ns.getCurrentPrice()); } handler.sendEmptyMessage(RESULT_OK); } catch (Exception e) { Log.e("StockPortfolioViewStocks", "Exception getting stock data", e); } } }; Thread dataThread = new Thread(task); dataThread.start(); }
在 清單 2 和 清單 3 中的代碼有兩個(gè)主要的不同。明顯的差異是 Handler 的存在。第二個(gè)不同是,在衍生線程中,您不能修改 UI。相反的,當(dāng)您將消息發(fā)送到 Handler,然后由 Handler 來(lái)修改 UI。也要注意,在線程中您不能修改 stocks 成員變量,正如您之前所做的。相反地您可以修改數(shù)據(jù)的本地副本。嚴(yán)格地來(lái)說(shuō),這是不是必須的,但這更為安全。
清單 3 說(shuō)明了在并發(fā)編程中一些非常普遍的模式:復(fù)制數(shù)據(jù)、將數(shù)據(jù)解析到執(zhí)行長(zhǎng)期任務(wù)的線程中、將結(jié)果數(shù)據(jù)傳遞回主 UI 線程、以及根據(jù)所屬數(shù)據(jù)更新主 UI 線程。Handlers 是 Android 中的主要通信機(jī)制,它們使這個(gè)模式易于實(shí)現(xiàn)。然而,清單 3 中仍然有一些樣本代碼。幸好,Android 提供方法來(lái)封裝和消除大多數(shù)樣本代碼。清單 4 演示了這一過(guò)程。
清單 4. 用一個(gè) AsyncTask 使多線程更容易
private void refreshStockData() { new AsyncTask<Stock, Void, ArrayList<Stock>>(){ @Override protected void onPostExecute(ArrayList<Stock> result) { ViewStocks.this.stocks = result; refresh(); } @Override protected ArrayList<Stock> doInBackground(Stock... stocks){ try { return fetchStockData(stocks); } catch (Exception e) { Log.e("StockPortfolioViewStocks", "Exception getting stock data", e); } return null; } }.execute(stocks.toArray(new Stock[stocks.size()])); }
如您所見(jiàn),清單 4 比起 清單 3 樣本代碼明顯減少。您不能創(chuàng)建任何線程或 Handlers。使用 AsyncTask 來(lái)封裝所有樣本代碼。要?jiǎng)?chuàng)建 AsyncTask,您必須實(shí)現(xiàn) doInBackground 方法。該方法總是在獨(dú)立的線程中執(zhí)行,因此您可以自由調(diào)用長(zhǎng)期運(yùn)行任務(wù)。它的輸入類型來(lái)自您所創(chuàng)建的 AsyncTask 的類型參數(shù)。在本例中,第一個(gè)類型參數(shù)是 Stock,因此 doInBackground 獲得傳遞給它的一組 Stock 對(duì)象。類似地,它返回一個(gè) ArrayList<Stock>,因?yàn)檫@是 AsyncTask 的第三個(gè)類型參數(shù)。在此例中,我也選擇重寫(xiě) onPostExecute 方法。這是一個(gè)可選方法,如果您需要使用從 doInBackground 返回的數(shù)據(jù)來(lái)進(jìn)行一些操作,您可以選用這種方法來(lái)實(shí)現(xiàn)。這個(gè)方法總是在主 UI 線程上被執(zhí)行,因此對(duì)于修改 UI 這是一個(gè)很好的選擇。
有了 AsyncTask,您就完全可以簡(jiǎn)化多線程代碼。它可以將許多并發(fā)陷阱從您的開(kāi)發(fā)路徑刪除,您仍然可以使用 AsyncTask 尋找一些潛在問(wèn)題,例如,在 doInBackground 方法對(duì)象執(zhí)行的同時(shí)設(shè)備上的方向發(fā)生改變時(shí)可能發(fā)生什么。更多關(guān)于如何處理這類案例的技術(shù),見(jiàn) 參考資料 的鏈接。
現(xiàn)在我們開(kāi)始討論另一個(gè)常見(jiàn)任務(wù),其中 Android 明顯背離常用的 Java 方法 — 使用數(shù)據(jù)庫(kù)進(jìn)行處理。
出處:CSDN
責(zé)任編輯:bluehearts
上一頁(yè) 享受Android應(yīng)用程序的Java技術(shù)盛宴 [2] 下一頁(yè) 享受Android應(yīng)用程序的Java技術(shù)盛宴 [4]
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|