Android多线程中的Handler机制、Looper的介绍与整理

在多线程的开发中,Handler机制如同在主线程中运行一样,只是需要注意在非主线程中Handler机制的使用限制,本文将对这些内容作出解释。

如果在子线程中对上UI界面进行操作,将抛出异常。为此,Android中引入了Handler消息
 传递机制,来实现在子创建的线程中更新UI界面,下面将对Handler消息传递机制进行介绍。


 一.Looper简介
 1.首先需要知道一个概念,那就是MessageQueue,在Android中,一个线程对应一个Looper对象
  ,而一个Looper对象又对应一个MessageQueue(消息队列)。MessageQueue用于存放Message,
  在MessageQueue中,存放的消息以队列的模式执行。
  2.Looper对象用来为一个线程开启一个消息循环,用来操作MessageQueue。默认情况下,Android
 中新创建的线程是没有开启消息循环的,但是主线程除外,系统自动为主线程创建Looper对象,开启消息循 环。所以,在主线程中,应用下面的代码创建Handler对象时,不会出错。而如果在新创建的非主线程中,应用下面的代码创建Handler对象时,将产生异常信息。
 如果想要在非主线程中,创建Handler对象,首先要使用Looper类的prepare()方法来初始化一个
  Looper对象,然后创建这个Handler对象,再使用Looper对象的loop()方法,启动Looper,从消息队列里
 获取和处理消息。

源代码分析 :

    
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }


    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;
        
        // 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();
        
        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.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("Looper", "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();
            }
        }
    }

    public void quit() {
        Message msg = Message.obtain();
        // NOTE: By enqueueing directly into the message queue, the
        // message is left with a null target.  This is how we know it is
        // a quit message.
        mQueue.enqueueMessage(msg, 0);
    }

再看下Handler的构造函数,在子线程中如果没有调用Looper.prepare()就new Handler()则会抛出异常。代码如下 :
    /**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn't one, this handler won't be able to receive messages.
     */
    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;
    }


 3.Looper对象
 提供了几个方法:
 prepare()----  用于初始化Looper
 loop()----   用于开启消息循环,当调用了loop()方法后,Looper线程就真正的开始工作了,它会从消息队列中
                      获取消息并处理消息
 quit()----   用于结束Looper消息循环
 
 注意:
 在loop()之后的代码不会被执行,这个函数内部是一个消息循环,除非调用quit()方法,loop()才会终止,
 其后面的代码才能得以运行。


源代码如下:

onCreate()方法:

[java]  view plain copy
  1. public class Thread_Handler_Activity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_thread__handler_);  
  7.         LooperHandler thread=new LooperHandler();  
  8.         thread.start();  
  9.     }  
  10.   
  11.     @Override  
  12.     public boolean onCreateOptionsMenu(Menu menu) {  
  13.         // Inflate the menu; this adds items to the action bar if it is present.  
  14.         getMenuInflater().inflate(R.menu.activity_thread__handler_, menu);  
  15.         return true;  
  16.     }  
  17.   
  18. }  

自定义线程类:

[java]  view plain copy
  1. public class LooperHandler extends Thread{  
  2.     public Handler handler;  
  3.   
  4.     @Override  
  5.     public void run() {  
  6.         // TODO Auto-generated method stub  
  7.         super.run();  
  8.         //初始化Looper对象  
  9.         Looper.prepare();  
  10.         //实例化一个Handler对象  
  11.         handler=new Handler(){  
  12.   
  13.             @Override  
  14.             public void handleMessage(Message msg) {  
  15.                 // TODO Auto-generated method stub  
  16.                 super.handleMessage(msg);  
  17.                 Log.d("BruceZhang""This is Test!!!");  
  18.             }  
  19.               
  20.         };  
  21.         Message msg=handler.obtainMessage();  
  22.         msg.what=1;  
  23.         handler.sendMessage(msg);  
  24.         Looper.loop();  
  25.     }  
  26.   
  27. }  

运行的结果是在日志中显示一条信息,如图所示运行结果:


但是,如果没有对Looper的声明,运行就会抛出如下的异常:


所以,在实际的应用中,应考虑Handler在哪一个线程的中的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值