Android学习笔记之消息机制

Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。

  1.为什么要使用Handler?

Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,则会抛出异常。同时Android建议不能在主线程中进行耗时的操作,不然会导致程序无法响应即ANR。因此耗时的工作只能交给子线程去做,而子线程却不能直接访问UI,为了解决这个矛盾,Android提供了Handler。Handler的主要作用是将某个任务切换到某个指定的线程中去执行。例如,我们在主线程中创建Handler,在子线程执行完耗时任务后,就可以通过Handler将更新UI的操作切换到主线程中去执行。

2.为什么系统不允许在子线程中访问UI?

因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。

3.Handler与MessageQueue,Looper

Android的消息机制主要是指Handler的运行机制,Handler的运行需要消息队列(MessageQueue)和消息循环(Looper)的支撑。

消息队列的内部存储结构并不是真正的队列,而是单链表。消息队列只是一个消息的存储单元,不能处理消息,而Looper就是来处理消息的。Looper会无限循环的去查看是否有消息,如果有,就处理,否则一直等待。

Handler创建时会采用当前线程的Looper来构造消息循环系统,如果当前线程没有Looper,则会报错(有的时候,也可以通过构造函数指定一个Looper)。这个当前线程的Looper是通过ThreadLocal来获取的。ThreadLocal并不是线程,它是线程内部的一个数据存储类,通过它可以在指定线性中存储数据和获取数据。

4.MessageQueue工作原理

         MessageQueue主要包含两个操作:插入和读取,分别对应enqueueMessage和next两个方法。enQueueMessage是往消息队列中插入一条消息,而next是从消息队列中取出一条消息并将其从消息队列中删除。前面说过,消息队列的内部实现是iyge单链表,它在插入和删除上比较有优势。

这里注意,next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞,当有新消息到来时,它会返回这条消息并将其从单链表中删除。

5.Looper的工作原理

  (1)Looper会一直不停的从MessageQueue中查看是否有消息,如果有,则会立刻处理,否则就一直阻塞。

为当前信线程创建Looper的方法如下:

new Thead("Thread1"){

  @override
   public void run()
  {
    Looper.prepare();
    Handler handler=new Handler();
    Looper.loop();
  }
}

注意,只有调用了Looper的loop方法后,消息循环系统才真正起作用。

loop方法会调用MessageQueue的next方法来获取消息,当没有消息时,next方法会阻塞,导致loop方法也会阻塞。Looper获得消息后,调用Handler对象的dispatchMessage方法,这个dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就就将代码逻辑切换到指定的线程中去了。

loop方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法返回null。当Looper的quit方法被调用时,它会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,其next方法就会返回null。

(2)Looper也可以退出,主要的方法是quit和quitSafely。前者会直接退出Looper,而后者只是设定一个标记,然后把消息队列中的已有消息处理完毕后才安全退出。Looper退出以后,Handler就无法再顺利发送消息了,其send方法会返回false。

(3)在子线程中创建Looper后,当所有事情完成以后应该调用quit方法来终止消息循环,否则这个子线程会一直处于等待状态。

  6.Handler的工作原理

Handler的主要工作是发送和接收消息。消息的发送通过post的方法和send的方法实现,post的方法最终是通过send的方法实现的。

Handler发送消息仅仅是向消息队列中插入一条消息,然后MessageQueue的next方法将消息给Looper处理,最终Looper将消息交给Handler处理,即Handler的dispatchMessage方法被调用。

public void dispatchMessage(Message msg){   if(msg.callback!=null)    {       handleCallback(msg);    }   else    {        if(mCallback!=null)          {

            if(mCallback.handleMessage(msg))               {                   return;
               }          }         handleMessage(msg);    } } 

这里msg.callback对象其实就是一个Runnable对象,就是Handler的post方法所传递的Runnable参数。

mCallback对应的类实现的是Callback接口。当我们不想派生Handler的子类并重写其handleMessage方法时,可以通过Callback来实现。

时间: 2025-01-09 08:52:33

Android学习笔记之消息机制的相关文章

Objective - C 学习笔记:消息机制的原理与使用

1.通知中心(NSNotificationCenter) 1.1.每一个应用程序都有一个通知中心(NSNotificationCenter*)实例,专门负责协助不同对象之间的消息通信 1.2.这就是观察者模式(Observer),任何一个对象都可以向通知中心发布通知(NSNotification*),描述自己在做什么.其他感兴趣的对象(Observer观察者)可以申请在某个特定通知发布时(或在某个特定的对象发布通知时)收到这个通知 2.通知(NSNotification) 2.1.一个完整的通知

十一、Android学习笔记_AsyncQueryHandler的应用

研究AsyncQueryHandler这个类的时候遇到了几个重要的不清楚的知识点 1. Handler与Thread,Looper的关系 2. HandlerThread是干什么用的 3. ThreadLocal类是干什么用的 Handler 主要是用来发送和处理消息,但是发送了消息后,消息是怎么传递的呢?这就是Looper的作用了,每个Handler中都会有一个Looper对象,如果在创建Handler的时候不指定,系统就会默认将当前线程的Looper绑定到Handler上,Looper对象中

Android学习笔记二十之Toast吐司、Notification通知、PopupWindow弹出窗

Android学习笔记二十之Toast吐司.Notification通知.PopupWindow弹出窗 Toast吐司 Toast吐司是我们经常用到的一个控件,Toast是AndroidOS用来显示消息的一种机制,它与Dialog不同,Toast不会获取到焦点,通常显示一段时间之后就会自动消失,下面我们来介绍Toast的几种常用方式: 第一种,默认显示方式,也是最常用的方式: Toast.makeText(MainActivity.this, "这是默认的显示方式", Toast.LE

[Android学习笔记]Android中多线程开发的一些概念

线程安全: 在多线程的情况下,不会因为线程之间的操作而导致数据错误. 线程同步: 同一个资源,可能在同一时间被多个线程操作,这样会导致数据错误.这是一个现象,也是一个问题,而研究如何解决此类问题的相关工作就叫做线程同步. android中,处理线程同步的手段就是:锁 一般分为公平锁和非公平锁: synchronized(内部锁,互斥锁):synchronized是JVM提供的线程同步机制,如果出现问题,JVM能捕获异常,并释放资源,具体实现机制需要查看JVM源码 synchronized的使用特

Android学习笔记五之Service

Android学习笔记五之Service 1.什么是Service? 什么是Service?Service是Android系统的四大组件之一,官方文档是这样描述Service的: A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application comp

Pro Android学习笔记(三三):Menu(4):Alternative菜单

什么是Alternative menu(替代菜单) 举个例子,Activity显示一个文本文件.如果用户想对文本文件进行编辑,Activity不提供编辑能力,但可由其他activity或者其他应用提供.我们将相关信息存储在一个intent中,例如该文本的Uri.这个intent可以匹配系统的多个应用,替代菜单将这些应用一一列出,菜单项的title就是该可被调用的activity的名字,图标也为该可被调用的activity的图表. 小例子说明 我们通过一个小例子进行学习,简单地打开一个URL:we

Android学习笔记_78_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>

Pro Android学习笔记(十):了解Intent(上)

Android引入了Intent的概念来唤起components,component包括:1.Activity(UI元件) 2.Service(后台代码) 3.Broadcast receiver(处理广播消息的代码) 4.Content provider(抽象数据的代码) Intent基本含义 intent是通知平台处理(唤起)的动作.Android唤起的动作将取决于注册了什么动作.例如我们有个简单的Activity:IntentBaiscViewActivity.在AndroidManife

Android学习笔记(十九):建立自己的ListView

在之前的例子中,我们通过设置adapter的getView()来编写我们所希望的UI,然而在面向对编程中,我们希望能够创建自己的ListView,例如类的名字为com.wei.android.learning.RatingView,只要在XML中用我们自己的RatingView对ListView来替代,就可以实现我们的风格,并前在源代码中向使用ListView一样简单调用就可以了. 实现的目标 在Android XML文件中,可以如下调用我们的RatingView: <com.wei.andro