Handler的工作原理,为什么在子线程中执行new Handler()会抛出异常?

Handler的工作主要包含消息的发送和接受过程。发送过程通过post的一系列方法和send的一系列方法来实现,post的一系列方法最终是通过send的一系列方法来实现的。发送一条消息的典型过程如下:  

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;

    if(mAsynchronous){

       msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg,uptimeMillis);

}

可以发现,Handler发送消息的过程仅仅是向消息队列中插入了一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终由Looper交由Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段。dispatchMessage的实现如下所示。

    public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            //Messagecallback是一个Runnable,      

           //也就是Handler post方法所传递的Runnable参数

            handleCallback(msg);

        } else {

            //如果给Handler设置了Callback的实现,

            //则调用CallbackhandleMessage(msg)

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            //调用HandlerhandleMessage方法来处理消息,

            //Handler子类需重写handlerMessage(msg)方法

            handleMessage(msg);

        }

}

 

Handler处理消息的过程如下:

首先,检查Message的callback是否为null,不为null就通过handleCallback来处理消息。Message的callback是一个Runnable对象,实际上就是Handler的post方法所传递的Runnable参数。handleCallback的逻辑也是很简单,如下所示。

private static void handleCallback(Message message) {

        message.callback.run();

}

其次,检查mCallback是否为null,不为null就调用mCallback的handleMessage方法来处理消息。Callback是个接口,它的定义如下:

    public interface Callback {

        public boolean handleMessage(Message msg);

    }

    //默认空实现

    public void handleMessage(Message msg) {

    }

Handler还有一个特殊的构造方法,可以指定一个特殊的Looper来构造Handler。

    public Handler(Looper looper) {

        this(looper, null, false);

    }

Handler创建需要Looper,否则会抛出异常,默认获取当前线程的Looper。主线程也就是ActivityThread会自动创建Looper,其他线程如果需要Looper均需要手动创建。

 

在子线程中是否可以创建一个Handler,仅仅通知线程呢?

new Thread(new Runnable() { 

            public void run() { 

                Handler handler = new Handler(){ 

                    @Override 

                    public void handleMessage(Message msg) { 

Toast.makeText(getApplicationContext(), "hadler msg", Toast.LENGTH_LONG).show(); 

                    } 

                }; 

                handler.sendEmptyMessage(1); 

                 

            }; 

        }).start(); 

很遗憾,会报错:

01-12 02:49:31.814: E/AndroidRuntime(2226): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),需要looper.prepare().

new Thread(new Runnable() {  

            public void run() {  

                Looper.prepare();  // 此处获取到当前线程的Looper,并且prepare()  

                Handler handler = new Handler(){  

                    @Override  

                    public void handleMessage(Message msg) {  

                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  

                    }  

                };  

                handler.sendEmptyMessage(1);  

                  

            };  

        }).start();  

1、Looper.prepare()是给这个Thread创建Looper对象,一个Thead只有一个Looper对象。

2、Looper对象需要一个MessageQueue对象一个Looper实例也只有一个MessageQueue。

3、调用Looper.loop();  不断遍历MessageQueue中是否有消息。

4、Handler 作用是发消息到MessageQueue,从而回掉Handler 的HandleMessage的回掉方法。

new Thread(new Runnable() {  

            public void run() {  

                Looper.prepare();  

                Handler handler = new Handler(){  

                    @Override  

                    public void handleMessage(Message msg) {  

                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  

                    }  

                };  

                handler.sendEmptyMessage(1);  

                Looper.loop();  

            };  

        }).start();  

这样就Ok了。

方法二:获取主线程的looper,或者说是UI线程的looper

这个方法简单粗暴,不过和上面的方法不一样的是,这个是通过主线程的looper来实现的

new Thread(new Runnable() {  

            public void run() {  

                Handler handler = new Handler(Looper.getMainLooper()){ // 区别在这!!!!  

                    @Override  

                    public void handleMessage(Message msg) {  

                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  

                    }  

                };  

                handler.sendEmptyMessage(1);  

            };  

        }).start();  


 

展开阅读全文

没有更多推荐了,返回首页