Android并发性实践
如果您在应用程序的主UI线程上运行清单1中的代码,可能会出现Application Not Responding对话框,具体视用户网络速度而定。因此必须确定生成一个线程来获取数据。清单2显示了一种解决方法。
清单2.Naïve多线程(别这样,这行不通!)
- privatevoidrefreshStockData(){
-
Runnabletask=newRunnable(){
- publicvoidrun(){
- try{
-
ArrayList<Stock>newStocks=
-
fetchStockData(stocks.toArray(
- newStock[stocks.size()]));
-
for(inti=0;i<stocks.size();i++){
-
Stocks=stocks.get(i);
- s.setCurrentPrice(
- newStocks.get(i).getCurrentPrice());
- s.setName(newStocks.get(i).getName());
- refresh();
- }
- }catch(Exceptione){
- Log.e("StockPortfolioViewStocks",
- "Exceptiongettingstockdata",e);
- }
- }
- };
-
Threadt=newThread(task);
- t.start();
- }
清单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
- privatevoidrefreshStockData(){
-
finalArrayList<Stock>localStocks=
-
newArrayList<Stock>(stocks.size());
- for(Stockstock:stocks){
- localStocks.add(newStock(stock,stock.getId()));
- }
-
finalHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
-
for(inti=0;i<stocks.size();i++){
- stocks.set(i,localStocks.get(i));
- }
- refresh();
- }
- };
-
Runnabletask=newRunnable(){
- publicvoidrun(){
- try{
-
ArrayList<Stock>newStocks=
-
fetchStockData(localStocks.toArray(
- newStock[localStocks.size()]));
-
for(inti=0;i<localStocks.size();i++){
-
Stockns=newStocks.get(i);
-
Stockls=localStocks.get(i);
- ls.setName(ns.getName());
- ls.setCurrentPrice(ns.getCurrentPrice());
- }
- handler.sendEmptyMessage(RESULT_OK);
- }catch(Exceptione){
- Log.e("StockPortfolioViewStocks",
- "Exceptiongettingstockdata",e);
- }
- }
- };
-
ThreaddataThread=newThread(task);
- dataThread.start();
- }
在清单2和清单3中的代码有两个主要的不同。明显的差异是Handler的存在。第二个不同是,在衍生线程中,您不能修改UI。相反的,当您将消息发送到Handler,然后由Handler来修改UI。也要注意,在线程中您不能修改stocks成员变量,正如您之前所做的。相反地您可以修改数据的本地副本。严格地来说,这是不是必须的,但这更为安全。
清单3说明了在并发编程中一些非常普遍的模式:复制数据、将数据解析到执行长期任务的线程中、将结果数据传递回主UI线程、以及根据所属数据更新主UI线程。Handlers是Android中的主要通信机制,它们使这个模式易于实现。然而,清单3中仍然有一些样本代码。幸好,Android提供方法来封装和消除大多数样本代码。清单4演示了这一过程。
清单4.用一个AsyncTask使多线程更容易
-
- privatevoidrefreshStockData(){
-
newAsyncTask<Stock,Void,ArrayList<Stock>>(){
- @Override
-
protectedvoidonPostExecute(ArrayList<Stock>result){
-
ViewStocks.this.stocks=result;
- refresh();
- }
- @Override
-
protectedArrayList<Stock>doInBackground(Stock...stocks){
- try{
- returnfetchStockData(stocks);
- }catch(Exceptione){
- Log.e("StockPortfolioViewStocks","Exceptiongettingstockdata",e);
- }
- returnnull;
- }
- }.execute(stocks.toArray(newStock[stocks.size()]));
- }
如您所见,清单4比起清单3样本代码明显减少。您不能创建任何线程或Handlers。使用AsyncTask来封装所有样本代码。要创建AsyncTask,您必须实现doInBackground方法。该方法总是在独立的线程中执行,因此您可以自由调用长期运行任务。它的输入类型来自您所创建的AsyncTask的类型参数。在本例中,第一个类型参数是Stock,因此doInBackground获得传递给它的一组Stock对象。类似地,它返回一个ArrayList,因为这是AsyncTask的第三个类型参数。在此例中,我也选择重写onPostExecute方法。这是一个可选方法,如果您需要使用从doInBackground返回的数据来进行一些操作,您可以选用这种方法来实现。这个方法总是在主UI线程上被执行,因此对于修改UI这是一个很好的选择。
有了AsyncTask,您就完全可以简化多线程代码。它可以将许多并发陷阱从您的开发路径删除,您仍然可以使用AsyncTask寻找一些潜在问题,例如,在doInBackground方法对象执行的同时设备上的方向发生改变时可能发生什么。更多关于如何处理这类案例的技术,见参考资料的链接。
现在我们开始讨论另一个常见任务,其中Android明显背离常用的Java方法——使用数据库进行处理。
分享到:
相关推荐
在Android应用程序中,有一类特殊的消息,是专门负责与用户进行交互的,它们就是触摸屏和键盘等输入事件。触摸屏和键盘事件是统一由系统输入管理器InputManager进行分发的。也就是说,InputManager负责从硬件接收...
让我们将您的网站和Web应用程序转换为Android应用程序。此应用程序模板支持各种Web应用程序/网站(包括HTML,PHP,WordPress,Progressive Web Apps,HTML 5 Games,WiX,Jimdo,apprat.io,bubble,Webflow,...)...
Android应用程序设计教程,主要内容包括Android开发环境构建、Android屏幕布局、Android控件Widgets、Android的图形用户界面、Android数据存储和Android多媒体。最后两个综合实训项目(手机乐游和基于Android的手机...
一个演示如何创建模糊和磨砂背景效果的Android应用程序_Java_下载.zip
移动操作系统原理与实践——基于Java语言的Android应用开发 目录 基础篇 第1章移动操作系统概论 1.1操作系统的原理与概念 1.1.1隐藏硬件细节 ...第3章第一个Android应用程序 3.1使用Android Studio工具创建项目
7个经典Android应用程序实例源代码.rar Android 培训--18个单项功能实例源码.rar Android 小项目开发示例大全--20个通用具体应用程序实例源码.rar Android 文件下载功能Java多线程下载功能的例子实例源码.rar ...
[14本经典Android开发教程]-4-Android应用程序开发36技 本书共分为4篇: ※ 第一篇:介绍应用框架概念、原理和特性。 ※ 第二篇:阐述应用框架之设计技巧。亦即,如何打造应用框架。 (注:如果你的职务是「使用」...
本教程介绍如何在 Eclipse 环境中进行 Android 应用程序开发,包括两个示例应用程序。第一个示例是一个基本的应用程序,涉及构建和调试的...开发 Android 应用程序需要 Java™ 编程技能,但是对于本教程不是必需的。
本书是Java语言学习指南,特别针对使用Java...第2部分(第23章到第50章)主要介绍如何有效地构建Android应用程序。本书适合任何想要学习Java语言的读者阅读,特别适合想要成为Android应用程序开发人员的读者学习参考。
java 计算器 用java 实现的android计算器应用程序。
7个经典Android应用程序实例源代码.rar Android 培训示例大全--18个单项功能实例源码.rar Android 小项目开发示例20个通用具体应用程序实例源码.rar Android 文件下载功能Java多线程下载功能的例子实例源码.rar ...
密西西比河谷州立大学:Android应用程序开发源代码,配合着网上课程来用回更好喔
88个经典Android应用程序打包下载[源代码],程序经典,比较适合初学者。
Android应用程序开发之二JAVA入门教程.pptx
鉴于此,《Android SDK程序设计与开发范例》首先让读者熟悉Android使用的XML和Java语法,然后才开始创建Android应用程序,介绍使用界面、事件处理、多活动Android应用程序,学习数据存储与数据交换、数据库和内容...
用于按位置记录Wifi信号强度的Android应用程序_Java.zip
ProbeDroid 一个用于Android应用程序的动态Java代码工具包
在您的Android设备上使用此Android应用程序在您的移动的手机中收听您最喜爱的电台直播。使用功能强大且响应迅速的管理面板,可以管理无限的电台和支持多种格式的类别,此应用程序由Android应用程序创建。支持几乎...
《Android SDK程序设计与开发范例(Android4.x/3.x/2.x全适用)》共分4部分,内容上循序渐进,从讲解Android使用的XML和Java语法开始,进而介绍创建单一活动的Android应用程序,详细说明Android使用界面和事件处理,...
订餐程序( java 和android开源程序,适用于学习) 里面还包含了一些google的天气查询等等