Handler的工作原理。为啥在子线程中使用Handler会抛出异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler的工作原理。为啥在子线程中使用Handler会抛出异常相关的知识,希望对你有一定的参考价值。

参考技术A Handler了它在安卓中常见的工作就是子线程与主线程的通信,其实可以直接归类为线程和线程间的通信

谈到Handler会涉及到以下几个类
Handler、Message、Looper、MessageQueue
我们一个一个来说,首先设置场景在一个线程中通知另一个线程

1,创建Looper和创建MessageQueue
首先在一个线程里要用Handler,那么需要准备Looper,调用Looper.prepare(),我们在主线程里面不用准备Looper,那么是因为在我们的主线程中已经给我们初始化好了Looper,
在准备Looper的时候会去校验这个线程中是否存在Looper,如果有Looper那么抛出异常(注意:有一些面试官会问如何判断一个线程中是否存在一个Looper的,它用的是ThreadLocal,它的作用是在线程范围内保证变量的唯一性,Thread中会维护一个类似HashMap的东西,然后用ThreadLocal对象作为key,value就是要存储的变量值,这样就保证了存储数据的唯一性)
如果没有Looper那么new一个Looper,new Looper的同时会new 一个MessageQueue(注意:一个线程中只有一个Looper一个MessageQueue)
然后Looper.loop()就可以启动轮训来轮训消息队列了
2,创建Handler
这个我们在熟悉不过了,继承一个Handler然后复写handlerMessage方法,这里其实面试官也可以问一些比较细致的问题,如下

注意:有面试官会问可以创建几个Handler,我负责任的说是多个,哪个Handler发送的消息哪个Handler处理(吐槽一下有的面试官,你自己把自己要问的问题搞清楚了在去问别人,非要跟我犟只能创建一个)

3,创建Message
Message一般都是使用Message.obtain(),它这里面是有一个spool指向一个Message对象,还有一个next指向下一个Message,它里面维护了一个链表,obtain的时候在表头头取Message,在Message回收的时候在表头添加一个Message,类似栈,默认大小是50
4,消息的处理
Handler对象sendMessage发送消息放入的MessageQueue队列中,Looper轮训到它,然后就开始处理Message,Message会有一个target去记录是哪个Handler发送的它,会调用这个Handler中的dispatchMessage()方法,如果说Message中实现了CallBack那么调用Message中的CallBack,如果Handler中实现了Callback调用Handler中CallBack,否则就都调动Handler中的handleMessage方法

根据上面的原理分析,那就是因为你子线程中没有Looper,给他一个Looper就好了

Android--Handler的使用方法:在子线程中更新界面

本文主要介绍Android的Handler的使用方法。Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列。每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联。

  1.     Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器。2)线程间通信。在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息。当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Handler对象,就可以通过该对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。

◆ 通过Runnable在子线程中更新界面的例子

在onCreate中创建Handler
public class HandlerTestApp extends Activity { 
        Handler mHandler; 
        TextView mText; 
        /** Called when the activity is first created. */ 
       @Override 
       public void onCreate(Bundle savedInstanceState) { 
           super.onCreate(savedInstanceState); 
           setContentView(R.layout.main); 
           mHandler = new Handler();//创建Handler 
           mText = (TextView) findViewById(R.id.text0);//一个TextView 
       }
构建Runnable对象,在runnable中更新界面,此处,我们修改了TextView的文字.此处需要说明的是,Runnable对象可以再主线程中创建,也可以再子线程中创建。我们此处是在子线程中创建的。

Runnable mRunnable0 = new Runnable() 
    { 
                @Override 
                public void run() { 
                        // TODO Auto-generated method stub 
                        mText.setText("This is Update from ohter thread, Mouse DOWN"); 
                } 
    };

 创建子线程,在线程的run函数中,我们向主线程的消息队列发送了一个runnable来更新界面。
private void updateUIByRunnable(){ 
          new Thread()  
         {  
               //Message msg = mHandler.obtainMessage();  
              public void run()  
             { 

                   //mText.setText("This is Update from ohter thread, Mouse DOWN");//这句将抛出异常 
                   mHandler.post(mRunnable0);  
             }  
         }.start();

     }

◆ 用Message在子线程中来更新界面

  1.     用Message更新界面与Runnable更新界面类似,只是需要修改几个地方。
实现自己的Handler,对消息进行处理

    private class MyHandler extends Handler 
    {

        @Override 
        public void handleMessage(Message msg) { 
            // TODO Auto-generated method stub 
            super.handleMessage(msg); 
            switch(msg.what) 
            { 
            case UPDATE://在收到消息时,对界面进行更新 
                mText.setText("This update by message"); 
                break; 
            } 
        } 
    }

在新的线程中发送消息     
    private void updateByMessage() 
    { 
        //匿名对象 
         new Thread() 
         { 
                public void run() 
                { 
                    //mText.setText("This is Update from ohter thread, Mouse DOWN");

                    //UPDATE是一个自己定义的整数,代表了消息ID 
                    Message msg = mHandler.obtainMessage(UPDATE); 
                    mHandler.sendMessage(msg); 
                } 
         }.start(); 
    }



以上是关于Handler的工作原理。为啥在子线程中使用Handler会抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

Android--Handler的使用方法:在子线程中更新界面

在子线程中更新UI,只能使用Handler

Handler的使用

android 消息机制及其原理

深入了解Android Handler机制原理详解

Android Handler 消息机制原理解析