android高级---->Handler的原理

Posted Linux

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android高级---->Handler的原理相关的知识,希望对你有一定的参考价值。

  andriod提供了Handler来满足线程间的通信,上次在更新UI的时候也提到过Handler的使用,关于Handler的基本使用,参见博客(android基础---->子线程更新UI).今天我们深入Handler的源码,了解一个Handler的内部执行原理。

 

目录导航

  1.   Handler简单说明
  2.   ActivityThread的说明
  3.   Handler的预备分析
  4.   Handler的原理分析
  5.   友情链接

 

Handler简单说明

一、 在Handler的原理说明之前,我们列出相关的重要的类:

  • Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
  • Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
  • MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
  • Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper
  • Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

 

二、 Handler主要有两种用途:

  • 合理调度安排消息和runnable对象,使它们在将来的某个点被执行。
  • 将一个动作入队安排在非当前线程执行。

 

三、 Handler创建消息

  每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。

 

四、 Handler发送消息

  UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

 

五、 Handler处理消息

  UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。注意handler是主线程中的类。

 

ActivityThread的说明

一、 Android的一个apk在打开时,使用到的第一个类就是这个类。

这里我们不深入Android应用程序的启动原理了,ActivityThread是一个final类,不是一个线程类:

public final class ActivityThread 

 

二、 ActivityThread在创建的时候同时也启动了一个线程,这个线程就是一个异步线程。

他创建出了MessageQueue,并同时进行消息的轮 询,因此当这个应用程序在运行时,这个线程是一直都在的。这个线程就是应用程序的主线程,UI的处理等都是在这个线程处理的。在AcitivityThread这个类的是有一个main方法的。我们知道java应用程序的入口就是main方法。这就是程序的入口。我们来看ActivityThread的源代码:

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    SamplingProfilerIntegration.start();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());

    AndroidKeyStoreProvider.install();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

  这里我们重点关注两点,这个在Handler的原理分析中会做详细的说明:

  • Looper.prepareMainLooper();
  • Looper.loop();

 

Handler的预备分析

一、 首先程序在启动的时候,会执行ActivityThread类的main方法,如上我们提到两个重要的代码: Looper.prepareMainLooper();

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

  在他的prepare方法中,创建了一个Looper,并把它放在了ThreadLocal中:

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

 

二、 ActivityThread中的Looper.loop();

public static void loop() {
  // 进入当前线程的消息循环
final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn\'t called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) {
     // 从队列中取出消息 Message msg
= queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }
    // 分发消息 msg.target.dispatchMessage(msg);
if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn\'t corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }

  在msg.target.dispatchMessage(msg);方法中msg.target这是分发消息的Handler

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
     // 首先,处理Message自己的callback,调用其run方法 handleCallback(msg); }
else { if (mCallback != null) {
       // 其次,调用Handler自留的接口对象
if (mCallback.handleMessage(msg)) { return; } }
     // 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类可以重写这个方法 handleMessage(msg); } }

 

Handler的原理分析

我们仍旧用一个例子来加以说明Handler的原理,例子代码具体可以参见我的博客:(android基础---->子线程更新UI)。以下的分析我会帖出有关例子的重要代码:

一、 创建一个Handler,处理消息:

public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case UPDATE_TEXT:
                textView.setText("I Love you.");
                break;
            default:
                break;
        }
    }
}

 

二、 发送消息:

// 用handler处理上述问题
public void handlerUpdate(View view) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Message message = new Message();
            message.what = UPDATE_TEXT;
            handler.sendMessage(message); // 将Message对象发送出去
        }
    }).start();
}

 

三、 首先我们要创建一个handler,具体构造方法代码如下,这里由于是new Handler():callback=null,async=false

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can\'t create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

 

四、 接下来进行了我们消息的发送:handler.sendMessage(message),源代码如下:(中间我们省略了一些过程)

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}
  enqueueMessage(queue, msg, uptimeMillis)的代码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
  • 所谓发送消息就是把消息放入消息队列中的合适位置,并且把消息的target设置为本Handler对象。

 

五、 在上述Handler的预备分析当中,我们提到过Looper的loop方法,它负责从队列中取出消息,并且分发消息。

而且我们在Handler的dispatchMessage方法也了解到,分发的消息会由Handler的handleMessage方法处理:也就是我们创建的Handler的重写方法:

public void handleMessage(Message msg) {
    switch (msg.what) {
        case UPDATE_TEXT:
            textView.setText("I Love you.");
            break;
        default:
            break;
    }
}
  • 当队列中的消息处理的时候,也会找到当时送它来的Handler对象,
  • 调用其相应的dispatchMessage()方法
  • 调用其中的handleMessage()方法或者mCallback成员的handleMessage()方法来进行处理。

 

友情链接

 

以上是关于android高级---->Handler的原理的主要内容,如果未能解决你的问题,请参考以下文章

Android高级开发面试题以及笞案整理

2021最新Android中高级开发必知必会面试题以及答案整理

2021最新Android中高级开发必知必会面试题以及答案整理

2021最新Android中高级开发必知必会面试题以及答案整理

干货2021最新Android中高级开发面试宝典1296页PDF分享

2021最新Android中高级开发必知必会面试题以及答案整理