Handler、Looper、MessageQueue深入解析

前段时间,本人研究了一下Android的Handler的源码,结合网上其他帖子的讲解,现在对Handler做一个总结


1.我们为什么需要Handler?

众所周知,Handler是Android中用来处理异步的类,通常用来更新UI线程的界面。那我们为什么不能直接在子线程中更新呢?让我们来试想这样一种情况,假如有很多子线程同时更新主界面的话,势必会造成非常混乱的情况,所以Android提供了Handler来处理这个问题。


2.先来看Handler的用法

public class MainActivity extends Activity {

	private  class MyHandler extends Handler
	{
		@Override
		public void handleMessage(Message msg) {

			mTv.setText("100");
		}
		
	}
	
	final MyHandler handler = new MyHandler();
	
	private TextView mTv = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mTv = (TextView) findViewById(R.id.myTv);
		
		new Thread(new Runnable() {
			
			public void run() {

//				Looper.prepare();

				Message msg = new Message();
				msg.what = 1;
				msg.obj = "text";
				handler.sendMessage(msg);
	
//				Looper.loop();
			}
		}).start();

	}
}

可以看到,在子线程中封装的Message通过在主线程中定义的Handler投递到UI线程中处理,接下来我们来看看Handler是如何实现的,先来看看Handler的构造函数

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class
   
    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();        //获取调用线程的Looper
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;            //获取该Looper中的消息队列
        mCallback = callback;
    }

Handler获取了调用线程的Looper,请注意,是调用线程!!(原因请看接下来对Looper的分析)所以Handler只能在UI线程中被创建


接下来,发送消息

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) {
    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;                                  //target是一个Handler类型,就是把目标Handler设置为自己
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);     //把Message投递到消息队列中
}

结合图片理解




3.Looper分析

看了上面的图片,相信大家对Handler的发送消息过程有了一定的了解,接上文,现在消息在调用线程的Looper中的消息队列里。在分析Looper之前,我想问大家一个问题,刚刚的代码示例中,并没有Looper的身影,那UI线程的Looper是在哪里生成的呢?请看

//ActivityThread的main函数,此函数为Activity启动的入口
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());

        Process.setArgV0("
   
   
    
    ");

        Looper.prepareMainLooper();                         //看这里

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

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

        AsyncTask.init();

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

        Looper.loop();                                          //看这里

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

   
   

Looper出现了,先看第一个函数

static final ThreadLocal
   
   
    
     sThreadLocal = new ThreadLocal
    
    
     
     ();          //关键,线程局部变量

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

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));                                      //添加Looper
}

    
    
   
   

ThreadLocal是线程局部变量,它为每一个线程准备了一个独立的Looper,详细的讲解请看ThreadLocal多线程实例详解

至此,Android通过ThreadLocal巧妙的将Looper与调用线程关联了起来


接下来,看第二个函数Looper.loop()

    public static void loop() {
        final Looper me = myLooper();                       //取得当前线程的Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;               //取得Looper中的消息队列

        // 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);                //找到对应的Handler处理消息

            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.recycle();                                   //回收,以循环使用Message对象
        }
    }

我们可以看到,loop()将消息取出,并调用对应Handler的dispatchMessage()来处理消息

Handler开始处理消息了

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {                         //如果Message设置了callback
            handleCallback(msg);
        } else {
            if (mCallback != null) {                        //如果Handler设置了callback
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            
            //假如都没有设置,就交给子类处理
            handleMessage(msg);
        }
    }

最后,Handler调用覆写的handleMessage()开始处理消息了(我们一般采用这种方法)


至此,Handler发送、处理消息的流程已经讲完了,下面来对这个做一些总结

1.一个线程只能有一个Looper,但是可以有多个Handler

2.Handler更像是一个辅助类,它封装了消息投递、消息投递等接口

3.在子线程中使用Handler要注意调用Looper.prepare()和Looper.loop(),不然Handler无法正常工作












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值