消息循环概要

在默认情况下Thread线程类在run()方法的内容执行完之后就退出了,并没有消息循环关联的概念。

而在Android的消息处理机制中,消息存放在一个消息队列中,使得线程围绕这个队列进入一个无限循环,直到程序退出。

如果队列当中有消息,线程就会将消息取出来,并分发给对应的handler进行处理。

若队列当中没有消息,线程就会进入空闲等待状态,直到下一个消息到来从而唤醒线程。

1、Looper类

Looper类用来为一个线程跑一个消息循环。

调用Looper类的prepare()方法可以为当前线程创建一个消息循环
,并且该prepare()方法在没个线程中只允许执行一次。

源码:

/** * Initialize the current thread as a looper. This gives you a chance to * create handlers that then reference this looper, before actually starting * the loop. Be sure to call {@link #loop()} after calling this method, and * end it by calling {@link #quit()}. */public static final void prepare() {    if (sThreadLocal.get() != null) {        throw new RuntimeException(                "Only one Looper may be created per thread");    }    sThreadLocal.set(new Looper());}

此方法会调用Looper类的私有构造方法,创建Looper对象。

private Looper() {    // 私有构造方法,在prepare()方法里面调用    // 创建消息队列    mQueue = new MessageQueue();    mRun = true;    // 当前线程    mThread = Thread.currentThread();}

调用loop()方法即可进入循环并开始处理消息,直至循环结束。但不是单纯的死循环,当消息队列当中没有消息时,便阻塞在了loop的queue.next()中的nativePollOnce()方法中,此时主线程会释放cpu资源而进入休眠状态。

源码:

/** * Run the message queue in this thread. Be sure to call {@link #quit()} to * end the loop. */public static final void loop() {    // 进入当前线程的消息循环    Looper me = myLooper();    //获取Looper对象中的消息队列    MessageQueue queue = me.mQueue;    while (true) {        // 从队列中取出消息        Message msg = queue.next(); // might block        if (msg != null) {            if (msg.target == null) {                // No target is a magic identifier for the quit message.                return;            }            // other codes...            // 分发消息            msg.target.dispatchMessage(msg);            // 消息的target是Handler类型的对象            // other codes...            // 释放清理            msg.recycle();        }    }}

程序调用示例:

class LooperThread extends Thread{    private Handler mHandler;    @Override    public void run() {        Looper.prepare();        mHandler = new Handler(){            @Override            public void handleMessage(Message msg) {            }        }        Looper.loop();    }}

2、Handler类

Handler用来处理消息以及与消息队列关联的Runnable对象。

Handler有几个构造重载,如果构造时不提供Looper对象参数,则其会获取当前的Looper对象与其关联绑定。若构造参数中以及当前线程中都没有Looper对象的话,则会抛出一个运行异常。

每一个Handler对象都只和一个线程以及该线程的消息队列关联。

Handler主要有两个个作用:

(1)发送消息:通过sendMessage等方法将消息放入消息队列的合适位置,并将消息的target设置为该handler。

(2)分发消息:通过Looper.loop()方法,去调用消息对象的target(即发送此消息的Handler对象)的dispatchMessage()方法,该方法再调用被实现的handleMessage进行消息处理。

源码:

/** * Handle system messages here. */public void dispatchMessage(Message msg) {    // 首先,处理Message自己的callback,调用其run方法    if (msg.callback != null) {        handleCallback(msg);    }    else {        // 其次,调用Handler自留的接口对象        // 这个成员变量声明时的注释如下:        /**         * Callback interface you can use when instantiating a Handler to         * avoid having to implement your own subclass of Handler.         */        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        // 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类可以重写这个方法        handleMessage(msg);    }}

3、UI线程

由于线程在代码执行完后就会结束,因此为了让主线程一直运行下去就采取了死循环的办法。Looper.loop()方法本身不会导致应用卡死,真正卡死主线程的原因时在回调方法onCreate/onStart/onResume等操作时间过长,导致掉帧或ANR异常。同时Activity的生命周期都是依靠主线程的Looper.loop方法,当收到不同的Message消息时采取相应的措施,并回调对应的生命周期方法。

UI线程与子线程通信方式是通过子线程调用与UI线程关联的Handler对象的post方法或sendMessage方法来实现的。

一个线程可对应一个Looper与一个消息队列,但可以关联多个Handler。

Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法。但ActivityThread本身并不是一个线程,其并没有继承Thread类。

源码:

public static final void main(String[] args) {    // other codes...    // 创建主线程循环    Looper.prepareMainLooper();    if (sMainThreadHandler == null) {        sMainThreadHandler = new Handler();    }    ActivityThread thread = new ActivityThread();    thread.attach(false);    // other codes...    // 进入当前线程(此时是主线程)消息循环    Looper.loop();    // other codes...    thread.detach();    // other codes...}

main方法中为程序创建了主线程循环。
Looper类中的主线程创建方式为Looper.prepareMainLooper(),其他线程不该调用该方法。

/** * Initialize the current thread as a looper, marking it as an application's * main looper. The main looper for your application is created by the * Android environment, so you should never need to call this function * yourself. {@link #prepare()} */public static final void prepareMainLooper() {    prepare();    setMainLooper(myLooper());    // other codes...}

主线程的Looper对象创建好之后会存在Looper类的成员变量mMainLooper当中,通过一个get方法可以获取到:

/** * Returns the application's main looper, which lives in the main thread of * the application. */public synchronized static final Looper getMainLooper() {    return mMainLooper;}

这样程序中其他对象就可以获取到主线程的消息循环对象,从而与主线程进行通信。

更多相关文章

  1. Android(安卓)TCP通信的简单实例以及常见问题[超时/主线程阻塞]
  2. Android判断设备网络连接状态及判断连接方式的方法
  3. 几种在shell命令行中过滤adb logcat输出的方法
  4. Android(安卓)4.0 消息广播无法接收的原因
  5. Android(安卓)UI卡顿检测(一)——基于Handler机制的实现方案(线上方
  6. Android学习札记39:关于安全退出已创建多个Activity的应用(2)
  7. 【Shader】适合 Android(安卓)手机上 GrabPass 方法失效的热扭曲
  8. Android(安卓)VideoView播放本地视频短暂黑屏的解决方法
  9. [android]一个关于UDP和TCP的项目实践(二)

随机推荐

  1. Android开发资料推荐之20个Android游戏源
  2. 全志A20 Android(安卓)源码编译
  3. Android(安卓)databinding笔记
  4. Android(安卓)近百个项目的源代码,覆盖And
  5. Android(安卓)对话框Activity去除白色边
  6. [android] No resource found that match
  7. AndroidManifest.xml Activity 属性说明
  8. android中Socket的使用
  9. Android中Handler引起的内存泄露
  10. Android(安卓)Interface Definition Lang