Handler,Looper,MessageQueue的实现

所要用到的android源码路径:

ActivityThread源码路径:android-4.0.3_r1\frameworks\base\core\java\android\app\ActivityThread

Activity源码路径:android-4.0.3_r1\frameworks\base\core\java\android\app\Activity

Handler源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Handler

Looper源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Looper

Message源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Message

MessageQueue源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\MessageQueue


我们从使用handler发送一条message到接收进行处理的这个过程来理解Handler,Looper,MessageQueue的实现,在Activity主线程中,会默认

创建一个Looper对象,在这个Looper类中会创建一个MessageQueue的消息队列,然后主线程会调用Looper的的loop()方法循环遍历这个消息队

列,如果有消息则会通过Handler对象将消息传递到handlerMessage方法中进行处理,如果Hanlder对象为空也就是没有创建Hanlder对象则会将

这条消息丢掉。那么消息的发送是怎样的呢?我们创建一个Handler对象,使用这个对象发送Message,其实是使用Looper对象传递进来的

MessageQueue,通过这个消息队列的引用将Message放进消息队列中,由于Looper会遍历这个队列,所以Handler对象发送msg,将其放进消

息队列,Looper遍历消息队列将消息取出,然后传递给Hanlder进行处理,这样一个消息的发送与接收就完成了。

首先我们根据Handler的构造函数来了解Handler的几种使用方法,从API中我们知道Handler有四个构造函数,分别是:

		Handler()
		Handler(callback)
		Handler(looper)
		Handler(looper, callback)

一、不带参数的Handler()构造函数,其使用的是主线程默认的Looper对象以及MessageQueue

	Handler handler2 = new Handler(){
		
		public void handleMessage(Message msg) {
			
		};
	};
	
	handler2.sendEmptyMessage(30);
直接在Activity中new一个Handler对象,并且重载handlerMessage方法就能够实现Message的发送与接收。

二、Handler(callback)构造函数,带了一个Hanlder类中的一个Callable接口对象作为参数,看源码就能够很清楚知道,他的作用其实是将handlerMessage

方法给独立出去,也就是在Activity中如果handlerMessage中的代码量太多,使用这个构造函数去创建对象,就能够将handlerMessage方法不放在

Activity中。

public class MyHandler implements Handler.Callback{
	
	@Override
	public boolean handleMessage(Message arg0) {
		
		return false;
	}
}
先实现Hanlder.Callback接口,丛杂handlerMessage方法,在这里进行消息的处理

		MyHandler callback = new MyHandler();		
		Handler handler3 = new Handler(callback);
		
		handler3.sendEmptyMessage(20);	
在Activity中创建Handler对象,将Callback对象作为参数传递进去,然后使用handler发送Message,就能够在MyHandler中接收消息进行处理。

三、Handler(looper)构造函数,带了一个自定义的Looper对象作为参数,所以我们只要自定义一个Looper,然后将该Looper对象传递进去就能够正常

的进行消息发送与接收。但是我们不必要真的去自定义一个Looper类,我们只需要继承android已经实现好的HandlerThread线程,就能够自定义一个

Looper类

public class MyThread extends HandlerThread{

	//HandlerThread类是android中已经继承Thread的类,他已经帮你实现了Looper对象的创建
	//所以如果我们在实现Handler时,需要自定义Looper对象,则直接继承此类就行。
	public MyThread(String name) {
		super(name);
	}
	
	@Override
	protected void onLooperPrepared() {
		//这个方法是在Looper.loop()被调用前在线程HandlerThread的run方法中被调用
		//所以如果要在这之前做什么操作,就需要重载这个方法
		Log.i("MyThread", "onLooperPrepared");
		super.onLooperPrepared();
	}
}

		MyThread thread = new MyThread("thread");
		thread.start();		
		Looper looper = thread.getLooper();
		
		Handler handler1 = new Handler(looper){			
			public void handleMessage(Message msg) {
				
			}
		};
		
		handler1.sendEmptyMessage(10);

这样我们就能够使用自定义的Looper进行消息的发送与接收,而不必使用Activity帮我们已经创建好的默认的Looper对象。


四、Handler(looper, callback)构造函数,知道了前面三种构造函数之后,这种就能够很容易理解了:使用自定义Looper,将handlerMessage方法

从创建Handler对象的类中独立出去。

Handler的详细使用方法就介绍完了,接下来我们就来分析相关类的源码,来彻底了解其运作过程。

首先我们来看看Looper的实现过程,我们知道在创建一个Activity时,其主UI主线程ActivityThread中会默认创建一个Looper对象,那么这个对象是在

什么地方创建的呢?

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

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

        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

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

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

        Looper.loop();

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

step1:从上面ActivityThread源码中我们可以看见,这个main方法是主线程的启动的地方,首先他调用了Looper的静态prepareMainLooper()方法:

    public static void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        myLooper().mQueue.mQuitAllowed = false;
    }

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

    private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }
    public static Looper myLooper() {
        return sThreadLocal.get();
    }
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
在上面源码中我们可以看出,prepareMainLooper方法中调用prepare()方法创建了一个Looper对象,并将这个Looper对象放进了ThreadLocal中,将

Looper对象放进ThreadLocal中的作用是,ThreadLocal会维护Looper对象中变量的副本。具体可以参考ThreadLocal的使用方法。然后调用myLooper

方法从ThreadLocal中获取Looper对象,并将其赋值给主线程Looper对象的引用。在Looper构造函数中我们可以看见,他创建了一个MessageQueue

对象,同时获取了Looper对象所在当前线程的引用。这样一个Looper对象便创建成功。

step2: 然后判断主线程的Handler是否为空,如果为空则默认创建一个Handler对象,但是在源码中这个默认的Handler时候从来就没使用过,
估计是既然已经默认创建了Looper,那么也默认创建一个Handler对象。
step3: 创建主线程ActivityThread对象,然后调用loop()方法

    public static void loop() {
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        MessageQueue queue = me.mQueue;

        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        
        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;
                }

                long wallStart = 0;
                long threadStart = 0;

                // 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);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }

                msg.target.dispatchMessage(msg);

                if (logging != null) {
                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    if (logging instanceof Profiler) {
                        ((Profiler) logging).profile(msg, wallStart, wallTime,
                                threadStart, threadTime);
                    }
                }

                // 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.recycle();
            }
        }
    }

在loop方法中,首先获取之前创建的Looper对象,MessageQueue对象,清除所有之前的访问标志,然后下面就是一个while死循环,在这个while循环

中,通过Message msg = queue.next()不停的从消息队列中获取Message,然后判断获取的Message是否为空,不为空,则判断这个Message的target

是否为空,通过了解Message源码我们知道,这个target其实就是一个Handler对象,也就是如果在没有创建Handler对象,则这个Message不进行处理

直接返回,继续去下一个Message。如果已经创建了Handler对象,则通过msg.target.dispatchMessage(msg)将从消息队列中获取的Message传递

到Handler中。

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

在dispatchMessage中将消息传递到handlerMessage(msg)中,这样handler便接收到了一个Message。

通过上面三步,当一个Activity启动时,其主线程ActivityThread创建成功后,会默认创建一个Looper对象,一个消息队列。同时会循环遍历这个消息

队列,而不会管Handler对象有没有创建。

下面我们来看Handler是怎样发送一个消息进消息队列的,首先了解Hanlder的初始化过程:

    public Handler() {
        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 = null;
    }

从Handler的构造函数中我们可以看到,通过Looper.myLooper()获取Looper对象的引用,通过mLooper.mQueue获取消息队列的引用。

接下来我们看发送消息的方法:

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
从上面源码可以看到,调用sendMessage其实是调用sendMessageDelayed方法,在sendMessageDelayed方法中调用了sendMessageAtTime方法

sendMessageAtTime才是最终发送Message的地方,在sendMessageAtTime中我们可以看到,首先判断消息队列的引用是否为空,不为空则调用

enqueueMessage方法将Message放进消息队列中。在这个方法中我们还可以看到通过msg.target = this,Message获取到了当前Handler对象的引用

final boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }

要理解enqueueMessage源码,就必须结合Looper获取消息的方法来理解:

    final Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(mPtr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                final Message msg = mMessages;
                if (msg != null) {
                    final long when = msg.when;
                    if (now >= when) {
                        mBlocked = false;
                        mMessages = msg.next;
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    } else {
                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
                    }
                } else {
                    nextPollTimeoutMillis = -1;
                }

                // If first time, then get the number of idlers to run.
                if (pendingIdleHandlerCount < 0) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount == 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

在enqueueMessage中我们看到,首先判断Message的target即所属的Handler对象是否为空,为空则抛出RuntimeException异常,然后定义了一个

final boolean needWake变量,注意他没有进行初始化,而且为final类型,表明一旦其被初始化后就无法再次进行更改了,然后就是一个同步块,在

这个同步块中,首先获取一个全局Message对象mMessages的引用,如果这个Message不是延迟性或者空的消息,那么将这个msg赋值给这个全局

的Message对象mMessages,并且将mBlocked赋值给needWake,在MessageQueue源码中,可以看见mBlocked定义时是没有初始化的,那么

在哪里初始化呢?这就要看next()方法了。

我们知道在主UI线程创建时,Looper对象就会创建,就会调用loop()方法,就会调用next()方法循环遍历消息队列,由于一开始消息队列为空,所以

msg一定为空,执行的只是下面这段代码:

                if (pendingIdleHandlerCount < 0) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount == 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }
从这里就能够看见,mBlocked一开始是初始化为true的,所以在同步方法块执行完毕后,会调用nativeWake方法。在next()方法中可以看见,其消息

操作的逻辑也是一个同步方法块,而且注意到了没有?他操作的Message不是从什么队列中获取的,其实操作的就是那个全局的Message对象

mMessages,并且从MessageQueue的其他removeMessages等方法可以看到,所有操作全局对象mMessages都是在方法同步块中的,所以我们

就应该能够明白了MessageQueue不是用什么消息队列来保存Message的,而只是使用一个全局的mMessages来保存的,每次Looper循环遍历的

都是mMessages对象,获取到之后然后将这个对象置为空,如果next()在调用,则其他方法调用处于阻塞状态,如果enqueueMessage处于调用中

则其他调用的方法处于阻塞中,所以当有多个线程同时调用同一个Handler对象发送Message时,其中只有一个线程调用的方法是处于运行状态的,

其他线程的调用是处于阻塞状态的,为什么android会这样进行处理呢?我觉得这么处理的原因是以时间换取空间,Handler发送消息的逻辑是相对

简单的,没有什么业务逻辑,也就是所需获取执行的时间是非常短的,而且不会出现很多线程同时使用同一个Handler来发送Message。

所以到这里我们就明白了MessageQueue的实现机制了:

1、MessageQueue不是什么消息队列,没有使用到队列,其使用的是一个全局对象来进行消息接收与发送

2、MessageQueue中所有的消息操作方法都是同步块的,当有一个方法被执行时,其他方法是处于阻塞状态的。

3、如果我们同时开启非常多的线程使用同一Handler发送消息或者移除消息,那么sendMessage(msg)不会立即返回结果的。

4、在多个线程中不要大量使用Handler来操作Message。他只适合于少量线程中进行使用。

这样Handler的消息发送以及Looper的消息获取就都剖析完了。Handler,Looper,MessageQueue的实现也就完全讲完了。

总结:

在我们创建一个Activity时,会自动创建一个Looper对象,并且在Looper的构造方法中会创建一个MessageQueue的对象,当Activity的主线程启动

时,会调用Looper的loop()方法循环检查MessageQueue中的全局对象mMessages是否为空,如果不为空则会调用相应Handler的

dispatchMessage方法,将这个消息传递到Handler中的handleMessage方法中进行处理。当我们创建一个Handler对象,使用这个Handler对象

发送消息时,最终调用的是MessageQueue中的enqueueMessage,消息的所有的操作,如:发送,移除,遍历都是在MessageQueue中进行

操作的,这也对应了面向对象的及迪米特法则,也就是所有该类的职责应该就在该类中完成,尽量少于外界进行联系。消息的处理是单个操作的

当一个消息在发送时,其他消息的发送是处于阻塞状态,由于消息操作的业务逻辑简单,所以不必过于关注消息操作的延时性,但是不应在大量

线程中使用Handler进行消息传递。










评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值