关闭

Android消息处理机制

标签: android开发源码
782人阅读 评论(0) 收藏 举报
分类:
通常情况下使用Handler发送消息并且处理消息。

一:此时mHandler属于UI主线程。
private final Handler mHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
                    //其他代码
      }
  }
二:此时mHandler属于子线程(工作者线程)
class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }
new Handler()的时候做了如下工作:    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 ;
    }

至此:Looper = Thread + Handler 
                         ||
                         ||
                         ||

这种情况下,如果没有绑定对应的Looper对象,在此刷新Ui会抛出异常;
Can't create handler inside thread that has not called Looper.prepare()

为什么需要调用 Looper.prepare();Looper.loop();这两个方法:

先看看Looper类有些什么
 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//保存Looper变量,保证多个looper拷贝

    final MessageQueue mQueue;//消息队列
    final Thread mThread;//当前线程
当调用prepare()方法时做了些什么?

   public static void prepare() {
        if (sThreadLocal .get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }//检查该线程Looper实例变量是否为空,保证一个线程只有一个looper实例变量。
        sThreadLocal.set(new Looper());//这样sThreadLocal 就保存了当前线程的looper对象实例。
    }
                         ||
                         ||
                         ||
   private Looper () {
        mQueue = new MessageQueue();//一个Looper操作的消息队列
        mRun = true ;
        mThread = Thread.currentThread();//绑定到当前线程
    }
                         ||
                         ||
                         ||

public static void loop() {
        Looper me = myLooper();//获取与当前线程绑定的looper实例,
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        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(); // 取出消息
            if (msg != null) {

                    //msg.target 其实是一个Handler ,作用看后面
                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);//将消息处理转到msg.target 而看Message源码Handler target; 

                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();//
            }
        }
    }
                         ||
                         ||
                         ||
先看看Messenger有些什么?
    /*package*/ Bundle data;
   
    /*package*/ Handler target;    
   
    /*package*/ Runnable callback;//用于回调,  

    public void dispatchMessage(Message msg) {
       //先判断msg.callback是否为空或者不为空的情况?
          //问题1:而msg.callback是个线程,什么时候被初始化?
     if (msg.callback != null) {
            handleCallback(msg);
        } else {

            if (mCallback != null) {
                if (mCallback .handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//这里可以看出,最终消息发出后该消息会由Handler的handleMessage(msg);处理。
        }
    }
解答: //问题1:而msg.callback是个线程,什么时候被初始化?
    private final void handleCallback(Message message) {
        message.callback.run();//直接执行到传进来的线程的run方法中去了,即又回调回去了。
    }

Handler还有这样一中用法(即延迟处理消息):

new Handler().postDelayed( new Runnable() {
                         @Override
                         public void run() {
                             
                              //操作代码
                        }
                  }, 300);
------------>看postDelayed 方法:
    public final boolean postDelayed (Runnable r, long delayMillis)
    {
//传进来的线程被放进了getPostMessage(r)方法
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
------------>getPostMessage(r)方法

    private final Message getPostMessage(Runnable r) {
        Message m = Message. obtain();
        m.callback = r;//callback即被初始化了。则该消息的callback不为空
        return m;
    }
一路跟踪postDelayed的具体代码,最后到了sendMessageAtTime这个方法中来了。

上面一点说明了:handleCallback(msg);与 handleMessage(msg);的区别
                         ||
                         ||
                         ||
因此先看看sendMessageAtTime 这个方法:

public boolean sendMessageAtTime (Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;//问题1:这个是那里来的?也就是说这个是不是就是该线程绑定的looper的那个消息队列?
        if (queue != null) {
            msg.target = this;//问题2:当前Handler即为处理消息的目标handler
            sent = queue.enqueueMessage(msg, uptimeMillis);//处理消息
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue" );
            Log. w("Looper", e.getMessage(), e);
        }
        return sent;
    }

                         ||
                         ||
                         ||
处理消息放进来,拿出去的操作
 final boolean enqueueMessage(Message msg, long when) {
---------------开始-------------------------------------  
异常情况:消息正在使用;目标为空主线程不允许;   
   if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use." );
        }
//mQuitAllowed消息队列 是否允许结束标志位
   他的使用在这里: public static void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper ());
        myLooper().mQueue.mQuitAllowed = false;
    }而prepareMainLooper是在ActivityThread的时候调用,即初始化主线程的时候。说明他是与主线程挂钩的。

        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()+next()
                         ||
                         ||
                         ||
从Handler的源码看,Handler的所有发送消息方法中,不管以何种方式发送最后都会转到sendMessageAtTime这个
方法中。


另外:刷新UI的另外几种方式:

     runOnUiThread( new Runnable() {
                               public void run() {
               //代码
                  }
               });
                       |
                       |
                       |
    public final void runOnUiThread(Runnable action) {
               //判断是否是主线程,如果是则直接到这个线程的run方法中
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
                       |
                       |
                       |
    public final boolean post (Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }                       
后面的和上面一样了。最后还是回归到了r的run方法中


                   btn1.post(new Runnable () {

                         @Override
                         public void run() {
                               // TODO Auto-generated method stub

                        }

                  });


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:228594次
    • 积分:4067
    • 等级:
    • 排名:第7885名
    • 原创:123篇
    • 转载:31篇
    • 译文:1篇
    • 评论:54条
    最新评论