Android深入理解:Handler + Looper + Message

本文详细探讨了Android中的Handler、Looper和Message机制,它们构成线程间通信的基础。Handler用于发送和处理消息,Looper是消息循环管理者,Message作为任务载体。文章分析了它们的角色和交互方式,包括HandlerThread、IntentService的应用,以及主线程的消息处理流程,揭示了Android系统事件驱动的本质。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:本文是一篇对Handler相关内容的整理(经过相当一段时间,几次内容增减),有相当部分内容来源网络,其中融入部分作者本身的理解,并加以整理。如有涉及到哪位老师的原作,在此深表感谢!

目录

目录

Handler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)

1.Handler(生产者add)

1.1.Handler创建对象

1.2.Handler发送消息

1.3.Handler处理消息

1.4.Handler移除消息

2.HandlerThread

2.1.定义:

2.2.适用场景:

2.3.源码:

2.4.DEMO:

3.IntentService

3.1.定义:

3.2.源码:

3.3.DEMO:

3.3.1.多文件下载:

3.3.2.广播更新UI:

3.4.总结:

4.Looper(消费者get and deal)

4.1.定义:

4.2.机制:

4.3.应用:

1.ActivityThread

2.ActivityThread响应消息

3.ApplicationThread

4.IApplicationThread

5.App启动流程

4.4.quit:

5.Message(任务,产品)(Intent, Runnable, Message)

5.1.定义:

5.2.关键属性:

5.3.构造方式:

6.MessageQueue(任务队列,产品池)

6.1.定义:

7.应用案例

7.1.子线程发消息给子线程

7.2.主线程发消息给子线程

7.3.子线程发消息给主线程

7.4.AsyncTask

 


Handler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)

作者浅见。

Handler和Looper是多对一的关系,Looper和MessageQueue是一对一的关系。一个线程中,只有一个Looper 和 MessageQueue,但可以有多个Handler。Handler发送消息时,本身作为关联的target存入消息,Looper获取消息时,最终调用消息关联的Handler进行处理。

1.Handler(生产者add)

Handler:线程间通讯机制,是由Looper和MessageQueue来构建消息机制的。Handler发送消息给MessageQueue,并处理Looper分发过来的消息。

线程间通讯:

Handler在某线程把Message或者Runnable发送到目标线程的MessageQueue,然后由目标线程Looper对MessageQueue循环调度,再召唤发送消息的Handler进行处理。这个时候,处理过程:

@Override

public void handleMessage(Message msg) {
    super.handleMessage(msg);
}

将在Looper所属线程(目标线程)执行,即完成线程切换。

1.1.Handler创建对象

每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。

在主线程中(系统会为主线程自动创建Looper对象,开启消息循环)可以直接使用new Handler() 创建Handler对象,自动与主线程的Looper对象绑定。

new Handler() 等价于new Handler(Looper.myLooper())。Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。这种情况下,需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上;或者通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。

创建Handler对象,还可以通过传入Callback接口类型方式创建。

public Handler(Callback callback) {
    this(callback, false);
}
public interface Callback {
    public boolean handleMessage(Message msg);
}

1.2.Handler发送消息

Handler发送的消息都会加入到Looper的MessageQueue中。Handler只有一个消息队列,即MessageQueue。

关于:

handler.post(new Runnable() {
      @Override
      public void run() {
                        
      }
});

通过post()传进去的Runnable对象将会被封装成消息对象后传入MessageQueue;使用Handler.sendMessage()将消息对象直接加入到消息队列中。

使用post()将Runnable对象放到消息队列中后,当Looper轮循到该Runnable执行时,实际上并不会单独开启一个新线程,而仍然在当前Looper绑定的线程中执行,Looper只是调用了该线程对象的run()而已。如,在子线程中定义了更新UI的指令,若直接开启将该线程执行,则会报错;而通过post()将其加入到主线程的Looper中并执行,就可以实现UI的更新。

使用sendMessage()将消息对象加入到消息队列后,当Looper轮询到该消息时,就会调用Handler的handleMessage()来对其进行处理。再以更新UI为例,使用这种方法的话,就先将主线程的Looper绑定在Handler对象上,重载handleMessage()来处理UI更新,然后向其发送消息就可以了。

如果Handler对象与其调用者在同一线程中,如果在Handler的消息处理方法中设置了延时操作,则调用线程也会堵塞,因为Looper轮循是线性的,所以Handler处理Message的过程也是线性的。

1.3.Handler处理消息

Handler 在处理消息时,会有三种情况:

if :msg.callback 不为空

这在使用 Handler.postXXX(Runnable) 发送消息的时候会发生,直接调用 Runnable 的 run() 方法。

else if :mCallback 不为空

如果构造Handler时候以 Handler.Callback 为参数构造 Handler 时会发生,CallBack接口方法作为消息处理方法替代Handler.handleMessage() 执行处理操作。

Handler handler = new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message message) {
        return false;
    }
});

else :最后就调用 Handler.handleMessage() 方法

需要我们在 Handler 子类里重写

1.4.Handler移除消息

public final void removeCallbacks(Runnable r){

    mQueue.removeMessages(this, r, null);

}

public final void removeMessages(int what) {

    mQueue.removeMessages(this, what, null);

}

2.HandlerThread

2.1定义

HandlerThread 是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler。避免在子线程中对Looper手动繁琐的操作(Looper.prepare() ——> Looper.loop()),让我们可以直接在线程中使用 Handler 来处理异步任务。

HandlerThread 本身是一个Thread,需要start()启动。

HandlerThread 在run() 方法中为本线程创建了Looper(Looper.prepare()),调用 onLooperPrepared 后开启了循环(Looper.loop())

HandlerThread 需要在子类中重写 onLooperPrepared,做Looper启动前的初始化工作

HandlerThread 可以指定优先级,注意这里的参数是 Process.XXX 而不是 Thread.XXX

HandlerThread = Thread + Looper,适合在子线程中执行耗时的、可能有多个任务的操作的场景,比如说多个网络请求操作,或者多文件 I/O 等等。

2.2适用场景

为某个任务 / 回调单独开启线程,并提供由Handler + Looper提供任务(Message)调度机制。

个人理解:HandlerThread是一个可以通过Looper + Message 实现在子线程(Looper 和 MessageQueue在子线程,所以Looper循环消息,触发消息处理方法也是在子线程)中依次循环执行任务的线程类。

2.3.源码:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    /**
     * 子类需要重写的方法,在这里做一些执行前的初始化工作
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }
    //调用 start() 后就会执行的 run()
    @Override
    public void run() {
        mTid = Process.myTid();
	//创建了 Looepr
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();//Looper 已经创建,唤醒阻塞在获取 Looper 的线程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//开始循环
        mTid = -1;
    }
    /**
     * 获取当前线程的 Looper
     * 如果线程不是正常运行的就返回 null
     * 如果线程启动后,Looper 还没创建,就 wait() 等待 创建 Looper 后 notify
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }
    /**
     * Quits the handler thread's looper.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    /**
     * Quits the handler thread's looper safely.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

2.4.DEMO:

使用 HandlerThread 实现子线程完成多个下载任务。

DownloadThread,它有两个 Handler 类型的成员变量,一个是用于在子线程传递、执行任务,另一个用于外部传入,在主线程显示下载状态:

public class DownloadThread extends HandlerThread implements Handler.Callback {
    private final String KEY_URL = "url";
    public static final int TYPE_START = 1;
    public static final int TYPE_FINISHED = 2;
    /**
     * 外部传入,通知主线程显示下载状态
     */
    private Handler mUIHandler;
    /**
     * 内部创建,子线程传递、执行任务
     */
    private Handler mWorkerHandler;
    /**
     * download list
     */
    private List<String> mDownloadUrlList;
    public DownloadThread(final String name) {
        super(name);
    }
    /**
     * 执行初始化任务
     */
    @Override
    protected void onLooperPrepared() {
        super.onLooperPrepared();
        mWorkerHandler = new Handler(getLooper(), this);
        if (mUIHandler == null) {
            throw new IllegalArgumentException("No UIHandler!");
        }
        // 将接收到的任务消息挨个添加到消息队列中
        for (String url : mDownloadUrlList) {
            Message message = mWorkerHandler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString(KEY_URL, url);
            message.setData(bundle);
            mWorkerHandler.sendMessage(message);
        }
    }
    public void setDownloadUrls(String... urls) {
        mDownloadUrlList = Arrays.asList(urls);
    }
    /**
     * 获取主线程 Handler
     */
    public Handler getUIHandler() {
        return mUIHandler;
    }
    /**
     * 注入主线程 Handler
     */
    public DownloadThread setUIHandler(final Handler UIHandler) {
        mUIHandler = UIHandler;
        return this;
    }
    /**
     * 子线程中执行任务,完成后发送消息到主线程
     */
    @Override
    public boolean handleMessage(final Message msg) {
        if (msg == null || msg.getData() == null) {
            return false;
        }
        String url = (String) msg.getData().get(KEY_URL);
        //
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值