关于Handler几个小知识点

本文深入解析Android中的Handler机制,包括其工作原理、消息传递过程及如何避免消息处理混乱。同时,列举并解释了Android源码中使用Handler的典型类,如HandlerThread、IntentService和AsyncTask。

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

说到Handler想必大家都不陌生!Android中主要的消息机制也就体现在Handler上,在日常开发中最常见的操作就是通过Handler更新UI(子线程是不允许更新UI的)。

简要概括一下Handler机制

  • Handler在初始化过程中和Looper进行绑定,确切来说是为了和MessageQueue 进行绑定,有了MessageQueue消息队列就可以通过sendMessage等方法将Message对象加入到消息队列中
  • Looper通过loop方法进入到无限循环状态,有消息就处理最终回调到我们复写的方法handleMessage,无消息则进入阻塞等待。
  • Activity在创建的过程中会创建出Looper对象,所以在Activity中不要求创建Looper,但是如果新建子线程需要使用到Handler的话就需要通过Looper的prepare()方法创建出looper对象 。
  • 一个线程中只允许出现一个Looper对象,在Looper构造体中还会创建MessageQueue,这也间接保证MessageQueue对象的唯一。

Handler的原理如果还不是很了解的话可参考hongyang大神blog:

http://blog.csdn.net/lmj623565791/article/details/38377229

既然hongyang大神都对Handler已经总结那么好了,此处就不在多说些什么。本文是罗列出几个Handler知识点以及Android源码中究竟那些类使用到了Handler,你要是把这些相关知识也给面试官说一遍,那面试官在Handler这一块就真的没什么可问的了,(^__^) 嘻嘻……

Handler小知识点

  1. 同一个线程中可以new出多个Handler吗?使用多个Handler各自发送消息会不会混乱?
  2. Looper通过loop方法进入无限循环处理消息,那为什么主线程不会卡住呢?
第一个问题

首先肯定是允许new出多个Handler对象的,消息处理也不会混乱,哪个Handler发送的消息最终还是会交给它的handleMessage方法处理。怎么做到的呢?我们来看一下android源码

  //Handler class
  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);
    }

   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//将Handler对象放入Message
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

//Looper class 
public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            try {
                msg.target.dispatchMessage(msg);//Handler中的类我们已经知道msg.target指向Handler对象。
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...//省去部分代码
        }
    }

ok!Handler有很多发送消息的方法,最终都会调用sendMessageAtTime这个方法,方法中通过执行enqueueMessage方法将Message加入到MessageQueue中,看一下14行 msg.target = this; 这是什么?原来Message对象有target属性专门保存发送该消息的Handler对象,再看一下32行,Looper的loop方法中有 msg.target.dispatchMessage(msg);我们知道这个方法最终会回调到HandleMessage方法,msg.target 就是发送该消息的handler,这就一下子明白了,哪个Handler发送的Message最终还由它自己进行处理!

第二个问题

这个问题,我并不打算在陈述,请参考http://www.jianshu.com/p/72c44d567640 作者已经说了很明白。

以下是引用作者的总结:

主线程确实是阻塞的,不阻塞那APP怎么能一直运行,只不过是没有弄明白既然阻塞了,为什么还能调用各种声明周期而已.调用生命周期是因为有Looper,有MessageQueue,还有沟通的桥梁Handler,通过IPC机制调用Handler发送各种消息,保存到MessageQueue中,然后在主线程中的Looper提取了消息,并在主线程中调用Handler的方法去处理消息.最终完成各种声明周期.

Android使用到Handler的类

  • HandlerThread
  • IntentService
  • AsyncTask

    HandlerThread

    以往在子线程中创建Handler我们会做如下操作:

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

        public void stopLoop() {
            Looper.myLooper().quit();
        }
    }

6 7 13 17行这些代码是必须的。如果每次这样做岂不是很麻烦,所以android 给我们提供了HandlerThread 看一下源码

//HandlerThread class
 @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

//handler 初始化传递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;
    }
    //停止Loop的无限循环,也就意味着线程结束
 public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

看上面的HandlerThread方法和我们自己写的如出一辙,HandlerThread 优势在于帮我们创建了Thread和Loop对象,我们仅需要初始化Handler,如下是使用方法:

//我是在Activity的onCreate()方法书写的
  HandlerThread handlerThread = new HandlerThread("thread");
  handlerThread.start();
  Handler mHandler = new Handler(handlerThread.getLooper());

Note : 线程是异步的,start开始之后就会回调run方法,那么HandlerThread的run()方法已经和Handler的初始化异步了,怎么保证Handler初始化一定能拿到Looper对象?看源码中run(),和getHandler()中wait和notifyAll是不是一下子就明白了,JAVA加锁机制。

IntentService

服务主要作用就是提高运行权限等级在后台进行耗时操作,而我们又知道Service是在主线程上运行的所以一般在进行耗时操作需要自己创建出线程,将耗时操作交给子线程去做。IntentService是一个抽象类继承Service,我们需要复写onHandleIntent方法,如下是相关源码:

//IntentService class
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;

      private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        //Handler将回调消息,再次传给onHandleIntent
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

  @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    } 

     protected abstract void onHandleIntent(@Nullable Intent intent);

Service的生命周期第一次启动执行onCreate()—-onStart(),再次启动则直接执行onStart()。onCreate()作为入口那么我们先看一下这部分代码,初始化HandlerThread然后通过HandlerThread获取Loop对象创建Handler对象,这没什么,然后在看一下onStart()方法,onStart所做的事情就是通过Handler不断的发送消息。然后消息最终会毁掉给我们复写的onHandleIntent。

通过上面我们知道当我们多次startService(Intent intent),intent都会被包装到Message加入到消息队列中等待顺序执行。

使用IntentService具有以下优势:

  • 无需在Service中创建子线程
  • 当所有的任务执行完毕,Service会执行stopSelf方法,自动destory服务
AsyncTask

AsyncTask 请参考上一篇博客:http://blog.csdn.net/wning1/article/details/72852892 就明白AsyncTask 中Handler的运用了。

ok! 今天就记录到这。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值