WEB开发网
开发学院手机开发Android 开发 享受Android应用程序的Java技术盛宴 阅读

享受Android应用程序的Java技术盛宴

 2010-10-27 21:24:37 来源:Web开发网   
核心提示:清单 2 的标题声明这是 naïve 代码,确实是,享受Android应用程序的Java技术盛宴(3),在这个例子中,您将调用 清单 1 中的 fetchStockData 方法,在 doInBackground 方法对象执行的同时设备上的方向发生改变时可能发生什么,现在我们开始讨论另一个常见任务,将其封装在

清单 2 的标题声明这是 naïve 代码,确实是。在这个例子中,您将调用 清单 1 中的 fetchStockData 方法,将其封装在 Runnable 对象中,并在一个新线程中执行。在这个新线程中,您可以访问 stocks,一个封装 Activity(此类创建了 UI)的成员变量。顾名思义,这是 Stock 对象的一个数据结构(本例中是 java.util.ArrayList)。换句话说,您在两个线程之间共享数据,主 UI 线程和衍生(spawned)线程(在 清单 2 中调用)。当您修改了衍生线程中的共享数据时,通过在 Activity 对象上调用 refresh 方法来更新 UI。

如果您编写了 Java Swing 应用程序,您可能需要遵循一个像这样的模式。然而,这在 Android 中将不能正常工作。衍生线程根本不能修改 UI。因此在不冻结 UI ,但另一方面,在数据收到之后又允许您修改 UI 的情况下,您怎样检索数据?android.os.Handler 类允许您在线程之间协调和通信。清单 3 显示了一个使用 Handler 的已更新 refreshStockData 方法。

清单 3. 实际工作的多线程 — 通过使用 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 中的代码有两个主要的不同。明显的差异是 Handler 的存在。第二个不同是,在衍生线程中,您不能修改 UI。相反的,当您将消息发送到 Handler,然后由 Handler 来修改 UI。也要注意,在线程中您不能修改 stocks 成员变量,正如您之前所做的。相反地您可以修改数据的本地副本。严格地来说,这是不是必须的,但这更为安全。

清单 3 说明了在并发编程中一些非常普遍的模式:复制数据、将数据解析到执行长期任务的线程中、将结果数据传递回主 UI 线程、以及根据所属数据更新主 UI 线程。Handlers 是 Android 中的主要通信机制,它们使这个模式易于实现。然而,清单 3 中仍然有一些样本代码。幸好,Android 提供方法来封装和消除大多数样本代码。清单 4 演示了这一过程。

清单 4. 用一个 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()]));
}

如您所见,清单 4 比起 清单 3 样本代码明显减少。您不能创建任何线程或 Handlers。使用 AsyncTask 来封装所有样本代码。要创建 AsyncTask,您必须实现 doInBackground 方法。该方法总是在独立的线程中执行,因此您可以自由调用长期运行任务。它的输入类型来自您所创建的 AsyncTask 的类型参数。在本例中,第一个类型参数是 Stock,因此 doInBackground 获得传递给它的一组 Stock 对象。类似地,它返回一个 ArrayList<Stock>,因为这是 AsyncTask 的第三个类型参数。在此例中,我也选择重写 onPostExecute 方法。这是一个可选方法,如果您需要使用从 doInBackground 返回的数据来进行一些操作,您可以选用这种方法来实现。这个方法总是在主 UI 线程上被执行,因此对于修改 UI 这是一个很好的选择。

有了 AsyncTask,您就完全可以简化多线程代码。它可以将许多并发陷阱从您的开发路径删除,您仍然可以使用 AsyncTask 寻找一些潜在问题,例如,在 doInBackground 方法对象执行的同时设备上的方向发生改变时可能发生什么。

现在我们开始讨论另一个常见任务,其中 Android 明显背离常用的 Java 方法 — 使用数据库进行处理。

上一页  1 2 3 4 5  下一页

Tags:享受 Android 应用程序

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接