Handler

#建议跟随本笔记读源码、读官方文档说明,且牢记消息机制中涉及到的四个部分:Handler、Looper、MessageQueue、Message,分析中会着重强调它们之间的关系)

##请仔细阅读官方文档中关于Looper类的说明……这里截出官方给出的那个实例代码:
class LooperThread extends Thread {
public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      Looper.loop();
  }
}

我们的分析过程就是围绕这几行代码(首先注意到一点,这段代码是跑在子线程中的)。下面开始:
###1. Looper.prepare()方法:可以把Looper源码打开,先不去看这个prepare方法,先找到Looper的构造方法:

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

发现是私有的,即我们不能够在外部自己new出对象。再看这个无参prepare方法:

public static void prepare() {
    prepare(true);
}

发现会调用一个参数的prepare()方法:

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));
}

先注意到这里new了Looper对象了。这是第一次看到我们整个消息机制的四个部分的其中一个对象。

这里有一个***sThreadLocal*** 。不好解释,解释起来太长,给大家一个结论吧:首先明确一个叫做以线程为作用域变量的概念,ThreadLocal这个类型可以在不同的线程中维护一套数据的副本并且彼此互不干扰。(我是阅读《开发艺术探索》理解的)

### 2020.07.08更新,对于ThreadLocal的理解可参考笔者此篇

不管怎么说,程序到这一步,我们已经生成拿到了Looper对象。

###2. 再回到示例代码(new Handler一行):这里需要我们重写handleMessage()方法,有一个Message对象的参数,可以看一下Handler类关于这个方法的实现:

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {

}

一看发现为空,从上面的文档注释也可以知道,子类是需要重写这个方法,在这个方法中实现具体的处理消息的逻辑(比如更新UI)

###3. 从new Handler()对象开始:(使用无参构造作为分析入口)

/**
 * Default constructor associates this handler with the {@link Looper} for the
 * current thread.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 */
public Handler() {
    this(null, false);
}

无参构造会调用两个参数的构造方法:

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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;
}

注意标出的两行代码:

a. mLooper = Looper.myLooper();

b. mQueue = mLooper.mQueue;

从第一个开始:调用Looper.myLooper()方法,这时我们可以去看一下这个方法是干什么的。

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

又出现了这个sThreadLocal,先不管它,看它使用的方法:get,有get肯定有set,set实际上已经在前面见过了,(第1条prepare()方法中),从某种意义上讲,我们大致可以知道这里实际上就是返回一个Looper对象的引用,这个对象就是前面在prepare方法中new出来的。好,返回这个Looper对象的引用给了谁?mLooper。这是Handler的一个实例变量。那到这一步,我们的Handler对象和Looper对象是不是就建立联系了,即我们可以通过在Handler类中通过mLooper调用Looper对象中的方法了。


再往下看第二个红框:**b. mLooper.mQueue**,在Looper的源码中找到它:
**final MessageQueue mQueue;**
发现是个MessageQueue类型的引用,把这个引用赋给了Handler的成员mQueue,毫无疑问这个mQueue也是MessageQueue类型。那么这两个引用都指向哪个对象呢?或者说Looper中的mQueue是什么时候被初始化的呢?可以再回到Looper的私有构造方法:
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

嗯,在这里new出来了。

到这里,已经出现了Handler,Looper,MessageQueue三个组成部分了,而且这三者之间的关系是:组合关系,即Handler中同时持有Looper对象的引用和MessageQueue对象的引用,Looper中持有一个对MessageQueue对象的引用,对于Looper和MessageQueue它们的关系更紧密,因为是在Looper的构造方法中创建了MessageQueue对象,即这两个对象是成对出现的。关系图如下:

还差一个Message了,不要着急,下面我们马上开始sendMessage方法的分析。(注意,示例代码还有一行)

###4.sendMessage()方法:
首先这个方法需要传入一个Message对象,关于Message对象的创建有多种方式:由于构造方法是public的,所以可以自己new出来,但是官方建议:

While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

实际上底层维护了一个Message对象池(消息池)。

进入sendMessage()方法的实现:

/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

再跟进:

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

再跟进:

/**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
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);
}

可以停下来:这里就用上了Handler的mQueue成员(即一个消息队列,即前面在Handler构造方法中建立关联的那个MessageQueue对象)。再进enqueueMessage()方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

先看第一个红框:msg.target = thismsg,不就是我们从sendMessage传进来的那个Message对象。将这个Message对象的target成员赋值为this,this是谁?当前还是在Handler类中,那么这个this不就是Handler对象了嘛。再看这个target的定义:

/*package*/ Handler target;

那么我们的Handler和Message也建立关联了。现在补充完善前面画出的前三者之间的关系图:

好,再看第二个红框:***return queue.enqueueMessage(msg, uptimeMillis);***

这里流程已经从Handler类中跳到了MessageQueue中,我们来看enqueueMessage方法的实现,代码很多,我们就看这几行:

Message prev;
for (;;) {
 	prev = p;
    p = p.next;
    if (p == null || when < p.when) {
        break;
    }
    if (needWake && p.isAsynchronous()) {
       needWake = false;
    }
}

msg.next = p; // invariant: p == prev.next
prev.next = msg;

给出个结论吧,学过数据结构都知道,实际上这几行代码就是在执行单链表的插入操作,也就是说MessageQueue底层维护的Message型的单链表。那到这里,我们的消息已经放到了消息队列中。

###5.再来看示例代码的最后一行:
Looper.loop();

进入这个loop方法:

	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);
        }

首先这里是个死循环,只有next方法返回null才会退出,这也就应征下面这段话:

Looper:是每个线程的MesssageQueue的管家,调用Looper的loop方法后,就会进入到一个无限循环当中,每当发现MessageQueue中存在一个消息,就会将它取出,并传递到Handler中的handleMessage()方法中。每个线程中只会有一个Looper对象。

看代码旁边注释:might block。即可能会阻塞。那next的阻塞也就会造成loop的阻塞。再来看next方法:

if (prevMsg != null) {
      prevMsg.next = msg.next;
} else {
      mMessages = msg.next;
}

msg.next = null;

这几行是不是就是在执行链表结点的删除操作。在回到loop方法:
msg.target.dispatchMessage(msg);

注意这一行,调用了msg.target.dispatchMessage()的方法。这个msg.target是在哪里赋值的?前面已经提到,在

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

中的msg.target = this;

对,就是那个发送此消息的Handler对象,现在在loop方法调用了这个Handler对象的dispatchMessage()方法,现在流程又回到Handler类中,看这个方法的实现:

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

handleMessage(),就是我们在创建Handler对象时重写的那个handleMessage方法。到这里,我们的消息机制的整个流程就走完了。从sendMessage用来发送消息,最终又回到handleMessge方法中来处理消息。嗯,我已经对整个流程清楚了。


现在我们来看这样一个问题,就是我们在编写更改主界面时,并没有像示例代码中那样,先调用prepare(),最后再调用loop方法,这是为什么?这个时候,我们需要在Android源码中搜索ActivityThread.java源文件,打开它,查找“public static void main”,大概在4900多行,会找到一个熟悉的方法,main方法,

兴奋之余,再来看这个红框代码:调用Looper类的静态prepareMainLooper()方法,在Looper类中找到它的实现:

//终于在Android中找到久违的main方法了
public static void main(String[] args) {
    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());

    Security.addProvider(new AndroidKeyStoreProvider());

    Process.setArgV0("<pre-initialized>");
	
	//着重看这行代码
    Looper.prepareMainLooper();

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

兴奋之余,再来看这个红框代码:***Looper.prepareMainLooper();***

调用Looper类的静态prepareMainLooper()方法,在Looper类中找到它的实现:

 /**
 * 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.  See also: {@link #prepare()}
 */
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(false);//着重看这行代码

在这里调用了prepare()方法。找到了prepare方法,接下来去找loop方法在哪里调用的,再回到ActivityThread中的main方法:

Looper.loop();

所以,我们的整个步骤还是和示例代码是一样的,哪怕是主线程,也不会违背。

<think>嗯,用户想了解“handler”在编程或软件开发中的概念和用法。首先,我需要回忆一下自己对这个术语的理解。Handler这个词在计算机科学中确实很常见,但具体含义可能因上下文而异。比如,在事件驱动编程、网络通信、操作系统等不同领域,Handler可能有不同的应用场景。 首先,我应该从基础的定义入手。Handler通常翻译为“处理器”或“处理程序”,主要用于处理特定的事件、请求或数据。例如,在用户界面开发中,点击按钮会触发一个事件,这时候就需要一个事件处理函数(event handler)来响应这个动作。这种情况下,Handler的作用是定义当某个事件发生时应执行的代码逻辑。 接下来,可能需要分不同场景来详细说明Handler的用法。例如,在事件驱动编程中,Handler通常与事件监听器(event listener)配合使用,当特定事件被触发时,对应的Handler就会被调用。比如在JavaScript中,可以为按钮添加一个点击事件的Handler,当用户点击按钮时执行相应的函数。 然后,网络编程中的Handler也是一个重要应用。比如,在服务器处理客户端请求时,每个请求可能需要不同的处理逻辑,这时候可以通过不同的Handler来分发和处理请求。例如,使用Python的Flask框架时,可以通过装饰器定义不同URL路径对应的Handler函数,处理不同的HTTP请求。 另外,操作系统中的信号处理(signal handling)也是一个例子。当进程接收到操作系统发送的信号(如SIGINT中断信号)时,可以通过注册一个信号Handler来定义如何处理该信号,比如优雅地关闭程序或执行清理操作。 还需要考虑异步编程中的Handler,比如在Node.js中,回调函数(callback)就是一种Handler,用于处理异步操作完成后的结果。或者在使用消息队列时,消费者可能需要一个消息处理Handler来处理接收到的消息。 不过,用户可能已经对这些基本概念有所了解,所以需要进一步深入,或者提供一些具体实例。比如,可以结合代码示例,展示不同语言或框架中Handler的具体实现方式。例如,在JavaScript中的事件处理,或者Go语言中的HTTP请求处理。 同时,要注意到用户提供的引用内容。例如,引用[1]提到Go语言中使用goroutine来并发执行函数,这可能与异步处理或并发处理中的Handler有关。引用[2]讨论了I/O阻塞对CPU利用率的影响,或许在讨论网络请求处理时,如何高效使用Handler来避免阻塞。引用[3]关于消息代理的分发机制,可能与消息处理Handler相关。引用[4]似乎与许可证无关,暂时可以忽略。 因此,在回答时,可能需要结合这些引用中的相关内容,比如在Go语言中使用goroutine来处理并发请求,避免阻塞,提高CPU利用率。例如,在HTTP服务器中,每个请求可以启动一个goroutine来处理,这样主线程不会被阻塞,能够处理更多请求,提升性能。这种情况下,每个请求的处理逻辑可以视为一个Handler函数,由goroutine异步执行。 另外,消息代理中的Handler可能负责接收消息并分发给订阅者,确保消息的正确处理,如引用[3]所述。这种情况下,Handler需要处理消息的路由、确认、错误处理等,保证消息的至少一次或恰好一次传递。 总结来说,Handler的用途广泛,但核心都是处理特定的事件或请求。需要分场景说明,并结合代码示例和用户提供的引用内容,展示其在不同上下文中的具体应用和最佳实践。此外,生成的相关问题需要围绕Handler的不同应用场景、设计模式、性能优化等方面展开,帮助用户进一步探索。</think>### Handler 的概念与用法解析 在编程和软件开发中,**Handler(处理器)** 是一种用于**响应特定事件或管理特定任务**的代码模块。其核心作用是将程序逻辑与事件/请求的触发机制解耦,实现模块化和可维护性。以下是不同场景下的具体应用: --- #### 1. **事件驱动编程** 在图形界面(GUI)或前端开发中,Handler 用于处理用户交互事件(如点击、键盘输入)。 **示例**:JavaScript 中的点击事件处理器: ```javascript document.getElementById("myButton").addEventListener("click", function() { alert("按钮被点击!"); }); ``` - **功能**:当按钮被点击时,触发匿名函数执行弹窗操作[^1]。 --- #### 2. **网络请求处理** 在后端开发中,Handler 用于处理 HTTP 请求,并根据路由分发逻辑。 **示例**:Go 语言的 HTTP 处理器(结合 Goroutine 避免阻塞[^2]): ```go func main() { http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { go processRequest() // 使用 Goroutine 异步处理请求 fmt.Fprintf(w, "请求已接收") }) http.ListenAndServe(":8080", nil) } ``` - **功能**:当访问 `/hello` 路径时,异步处理请求并立即响应客户端。 --- #### 3. **消息队列与异步通信** 在分布式系统中,Handler 用于消费消息队列中的事件(如 RabbitMQ 或 Kafka)。 **示例**:消息代理中的订阅处理器[^3]: ```python def message_handler(channel, method, properties, body): print(f"收到消息:{body}") channel.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(queue="my_queue", on_message_callback=message_handler) ``` - **功能**:从队列中读取消息并确保至少一次交付。 --- #### 4. **操作系统信号处理** 在系统编程中,Handler 用于捕获和处理操作系统信号(如 `SIGINT`)。 **示例**:Python 中的信号处理器: ```python import signal import sys def signal_handler(sig, frame): print("接收到终止信号,优雅退出...") sys.exit(0) signal.signal(signal.SIGINT, signal_handler) ``` - **功能**:用户按下 `Ctrl+C` 时,执行清理逻辑后退出。 --- #### 5. **设计模式中的应用** Handler 也常用于责任链模式(Chain of Responsibility),将多个处理器串联以依次处理请求。 **示例**:日志处理链: ```java public abstract class Logger { protected Logger next; public void setNext(Logger next) { this.next = next; } public abstract void handle(String message); } public class ErrorLogger extends Logger { public void handle(String message) { if (message.contains("ERROR")) { System.out.println("错误日志:" + message); } else if (next != null) { next.handle(message); } } } ``` - **功能**:根据消息类型选择处理器,未处理则传递给下一环节。 --- ### 性能优化与注意事项 - **异步处理**:避免阻塞主线程,如 Go 的 Goroutine 或 Node.js 的异步回调。 - **错误处理**:在 Handler 中需捕获异常,防止进程崩溃(如网络请求超时)。 - **资源管理**:及时释放文件句柄、数据库连接等资源,避免内存泄漏。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值