Android应用程序中多线程应用的方法研究

摘 要:在Android应用程序中,如果UI线程(主线程)处理事件占用的时间过长,就会出现ANR(应用程序无响应)异常。因此,为了确保用户顺畅的操作体验,我们需要将耗时长的任务(如:访问网络获取数据、大量的数据计算)分配给后台线程处理。其中涉及到UI线程与非UI线程信息交互等相关问题。本文将主要讨论如何最佳构建应用程序来提高响应性能并避免ANR异常。

关键词:Android;ANR异常;多线程技术;异步任务

中图分类号:TP311.52

Android是基于Linux平台的开源手机操作系统,目前已广泛地使用于手机等移动设备。由于Android的开源性,基于Android应用软件的开发也有着很好的市场前景。为保证Android应用软件的良好用户体验,合理地分配UI线程和后台线程中所执行的任务是极为重要的。因此,在开发Android应用程序时,引入多线程技术可以有效地明确应用程序的结构,保证应用程序的灵活性,降低任务间的耦合度,使得所开发的应用软件能够更加高效地运行。

1 Android的相关知识

1.1 Android基本组件

一个Android应用程序由松散耦合的组件组成,并由应用程序清单绑定到一起。它主要由以下五个基本模块构成:

活动(Activity):Android应用程序的核心,形成显示信息的图形用户接口并响应用户事件。

服务(Service):一直在后台运行,可以更新数据源和可见活动并触发通知。

内容(Context):用来管理和共享应用数据库,实现多个程序之间的数据共享。

意图(Intent):一个应用程序之间传递消息的桥梁。通过意图,可以在系统范围内向目标活动或者服务广播消息,以说明执行某个动作的意图。

广播接收器(Broadcast Receiver):通过创建和注册广播接收器,应用程序可以监听到匹配特定过滤器的意图广播,广播接收器会自动启动应用程序响应某个意图,这个特点使其成为事件驱动应用程序的最佳选择。[1]

1.2 Android事件处理

在绝大部分情况下,应用程序需要及时对用户动作做出响应。因此,Android应用程序与用户的交互是十分重要的。要实现用户与应用程序的交互,就需要编写Java代码来创建事件处理。

Android事件处理是一种“委托事件处理模型”(Delegation Event Model),分为“事件来源”(Event Source)和处理事件的“监听者”(listener)对象。当事件发生时,注册的监听者对象可以接收事件,然后调用相关方法进行处理,监听者是一个委托处理设置事件的对象。[2]

2 Android系统中多线程信息交互具体方法

2.1 多线程技术的使用

Android的UI线程主要负责处理用户的按键事件、用户触屏时间及屏幕绘图事件等,因此其他的操作是不能够阻塞UI线程的,否则UI界面会停止响应。Android系统默认约定当UI线程阻塞超过20秒时,将会引发应用程序无响应异常(ANR)。

为避免上述现象的发生,Android建议将耗时的操作放在新的子线程中完成。Android开发框架中主要提供了两种解决方法(以通过网络下载大量资源为例):

(1)首先,程序需要启动一个新的子线程来获取下载资源文件,资源获取结束后通过Handler机制发送消息(Message),并同时在UI线程中处理消息,从而达到异步线程中处理事件的效果,然后通过Handler Message方法来更新线程。

(2)使用Android中提供的AsyncTask方式来完成异步操作。AsyncTask是使用java.util.concurrent框架来管理线程以及任务的执行的,concurrent框架是一个非常成熟、高效的框架,经过了严格的测试。这说明AsyncTask的设计很好的解决了匿名线程存在的问题。[3]

当Android应用程序启动主线程时,主线程主要负责处理与UI相关的事件,并将相关的事件分配给对应组件进行处理。为了保证线程的安全性,Android规定:只允许主线程修改Activity中的组件。但是,在实际开发中,很可能需要启动新的子线程修改UI组件的属性,这就需要利用到Handler的消息传递机制。

2.2 Handler消息传递机制

Handler类主要包括两个作用:在新启动的线程中发送消息;在主线程中获取、处理消息。通过回调的方式,主线程能够处理新启动线程所发送的消息。当新启动的线程发送消息时,消息会发送到与之关联的MessageQueue,而handler会不断从MessageQueue中获取并处理消息。

下面介绍与Handler类工作的三个组件:

Message:Handler接收和处理的消息对象。

Looper:每个线程只能拥有一个Looper。它的loop方法负责读取MessageQueue中的消息,读到消息后就把消息交给发送该消息的Handler进行处理。

MessageQueue:消息队列,它采用先进先出的方式来管理Message。

处理过程如图1所示。

图1

Looper对象与对应的子线程绑定,在初始化Looper时,会创建一个与之相关联的MessageQueue,这个MessageQueue负责管理该子线程的消息。

每一个线程只能拥有一个Looper,它的loop方法负责读取MessageQueue中的消息,读到消息之后将其交给Handler处理。为确保Handler能够正常工作,当前的线程必须有一个MessageQueue,而MessageQueue又是由对应的Looper负责管理的,所以启动一个子线程时,必须为其创建一个Looper对象并启动它。

需要说明的是,在主线程中,系统已经初始化了一个Looper,因此只需创建一个Handler即可。[4]

2.3 AsyncTask

相对于Handler消息传递机制,AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。

AsyncTask是抽象类,它定义了如下三种泛型类型:

(1)Params:启动任务执行的输入参数的类型。

(2)Progress:后台任务完成的进度值的类型。

(3)Result:后台执行任务完成后返回结构的类型。

使用AsyncTask主要分为三步:

(1)创建AsyncTask的子类,并为三个泛型参数指定类型;

(2)实现AsyncTask下面的几个方法:

doInBackground(Params…):重写该方法指定后台线程将要完成的任务。

onProgressUpdate(Progress...values):在调用publishProgress(Progress...values)时,此方法被执行,直接将进度信息更新到UI组件上。

onPreExecute():该方法在执行后台耗时操作前被调用,通常用于完成初始化的准备工作。

onPostExecute(Result result):当doInBackground()完成后,系统调用该方法,将后台计算的结果传递到UI线程中。

(3)调用AskncTask的子类的execute()方法执行耗时的任务。

Android提供的AsyncTask类实质上是Handler与Thread的封装。因此,我们可以直接继承AsyncTask类,并在类中实现相关的异步操作,利用类中提供的接口实现UI进度的更新。

2.4 Handler机制与AsyncTask的比较

Handler机制与AsyncTask均能够在Android中实现异步任务机制,由于它们各自不同的特点适用的环境也不尽相同。

Handler机制中涉及到Handler、Looper、Message、Thread四个对象,能够清晰地将不同的后台任务进行划分,有利于理解各个任务的实质与功能,对于整个过程的控制比较精细。但是,当其用于处理单一的后台任务时,相比于AsyncTask,其结构显得相对复杂,代码段也较为臃肿,不易精确地控制任务。

AsyncTask的实现原理较为简单,因此在使用其实现异步任务时会更加快捷。但是,当有多个异步操作需要访问或变更UI组件时,处理过程就会变得复杂。

3 结束语

本文就Android操作系统应用层的工作机制做了大致的介绍,并且分析了利用多线程技术来提高应用软件相应性能以及避免ANR异常的方法。具体说明了Android框架中2种用于避免UI线程阻塞的机制即Handler消息传递机制和异步任务机制,并且对两者做出了简要的比较。

总的来说,开发Android应用程序时需要利用上述的两种机制将耗时多的任务分配给后台的子线程,这样能够减轻UI线程的负担,减小发生ANR的可能性,并进一步提高用户体验。

参考文献:

[1]闫伟,叶建栲.多线程技术在Android手机开发中的应用[J].信息通信,2012(01).

[2]陈会安.Android SDK程序设计与范例[M].北京:清华学出版社,2012.

[3]杨杰.基于Android的多线程处理技术[J].电脑知识与技术,2013.

[4]李刚.疯狂Android讲义第二版[M].北京:电子工业出版社,2013.

作者简介:肖柏昀(1993.09-),女,湖北人,研究方向:计算机应用。

作者单位:华中师范大学计算机学院,武汉 430079

推荐访问:多线程 应用程序 方法 研究 Android