当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行.

当一个程序第一次启动时,Android会同时启动一个对应的 主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事 件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线 程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

我们不可以在子线程中更新UI元素

注重子线程和UI线程的交互

MessageQueue Handler Looper 下面对它们进行详细说明

在单线程模型下,为 了解决类似的问题,Android设 计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组 件进行信息交换。
l Message Queue

Message Queue是一个消息队列,用来存放通过Handler发 布的消息。消息队列通常附属于某一个创建它的线程,可以通过Looper.myQueue()得 到当前线程的消息队列。如果没有消息队列对象则会抛出空指针异常 。Android在 第一次启动程序时会默认会为UI thread创建一个关联的消息队列,用来管理程序的一些上层组件,activities,broadcast receivers 等等。你可以在自己的子线程中创建Handler与UI thread通讯。也就是说我们程序一启动我们的UI线程也就是主线程就会有一个消息队列 ,而如果我们自己另外开启的一个子线程就不会有MessageQueue(消息队列)对象。这一点大家务必知道。

Handler

通过Handler你 可以发布或者处理一个消息或者是一个Runnable的 实例。每个Handler都 会与唯一的一个线程以及该线程的消息队列关联。当你创建一个新的Handler时候,默认情况下,它将关联到创建它的这个线程和该线程的消息队列。也就是说,如果你通过Handler发 布消息的话,消息将只会发送到与它关联的这个消息队列,当然也只能处理该消息队列中的消息。

这里请允许我多说一句就是 我们把消息放进去的一端 消息不会阻塞但是处理消息的一端就有可能会阻塞。


l Looper

Looper扮演着一个Handler和 消息队列之间通讯桥梁的角色。程序组件首先通过Handler把 消息传递给Looper,Looper把 消息放入队列。Looper也 把消息队列里的消息广播给所有的Handler,Handler接 受到消息后调用handleMessage进 行处理。

1) 可以通过Looper类 的静态方法Looper.myLooper得 到当前线程的Looper实 例,如果当前线程未关联一个Looper实 例,该方法将返回空(null)它不户抛空指针。

2) 可以通过静态方法Looper. getMainLooper方法得到主线程的Looper实 例 这里需要注意一下 主线程默认是有Lo是oper对象的。但是我们自己定义的子线程没有的。那么我们怎么在子线程中得到Looper对象呢?如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以再其他的线程中通过 Handle来做,但前提是我们的Hanle知道这个子线程的Looper,但是你如果不是在子线程运行 Looper.myLooper(),一般是得不到子线程的looper的。


累了吗?可以去喝喝茶。回来我们继续。下面我们 来看看人人皆知的AsyncTasks类 Async就是异步的意思,然后Task是任务的意思。翻译过来就是 异步任务了。首先我要告诉你它是用来捣鼓线程的。 这是你必须要一定要产生一个疑问就是 这个类的处理方式和我们上边写的那种 用 Hadler Looper MessageQueue 处理的方式有什么不同??? 好了这个类我们是必须会。必须会用。必须地。


其实平常一般都是使用AsyncTask的,而并非Thread和Handler去更新UI,这里说下它们到底有什么区别,我们平时应该使用哪种解决方案。从Android 1.5开始系统将AsyncTask引入到android.os包中,过去在很早1.1和1.0 SDK时其实官方将其命名为UserTask,其内部是JDK 1.5开始新增的concurrent库,做过J2EE的网友可能明白并发库效率和强大性,比Java原始的Thread更灵活和强大,但对于轻量级的使用更为占用系统资源。Thread是Java早期为实现多线程而设计的,比较简单不支持concurrent中很多特性在同步和线程池类中需要自己去实现很多的东西,对于分布式应用来说更需要自己写调度代码,而为了Android UI的刷新Google引入了Handler和Looper机制,它们均基于消息实现,有时可能消息队列阻塞或其他原因无法准确的使用。

推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,Google在Browser中大量使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是AsyncTask相比Thread加Handler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即dobackground方法执行后无法给线程发送消息,仅能通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用Thread和Handler以及Looper可能更灵活。

那么先让我们看看要使用AsyncTask 类首先要做哪些工作?
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute() 开始执行前的准备工作;
doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。

这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程所调用的,所以要求:
1) AsyncTask的实例必须在UI thread中创建;
2) AsyncTask.execute方法必须在UI thread中调用;

同时要注意:该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止的,这一点要注意,看是否符合你的需求!

在使用过程中,发现AsyncTask的构造函数的参数设置需要看明白:AsyncTask<Params, Progress, Result>
Params对应doInBackground(Params...)的参数类型。而new AsyncTask().execute(Params... params),就是传进来的Params数据,你可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据。
Progress对应onProgressUpdate(Progress...)的参数类型;
Result对应onPostExecute(Result)的参数类型。
当以上的参数类型都不需要指明某个时,则使用Void,注意不是void。

http://blog.csdn.net/chenlei1889/archive/2011/04/15/6326536.aspx

更多相关文章

  1. Android 中的线程
  2. Android消息机制Handler的实现原理解析
  3. 浅析android线程模型【Android】
  4. Android底下多线程下载远程图片
  5. Android消息机制,从Java层到Native层剖析

随机推荐

  1. 这些node开源工具你值得拥有(上)
  2. php.ini 配置文件的深入解析
  3. Oracle 9i产品文档
  4. 实现core文件自动生成配置文件的方法
  5. RHEL6.5下JDK1.8安装教程
  6. 临摹应该从哪里开始?绘画中的临摹技巧
  7. tensorflow-cpu/gpu速度 cpu(3分钟)vs gpu(4
  8. php中Workerman框架实例讲解
  9. PHP优化教程之解决嵌套问题
  10. php中unable to fork报错简单解决方法