• handler looper messageQueue 之间的关系笔记


    handler 主要用于发送消息和接收消息,handler可以更新ui延时更新ui
    looper 主要用于从消息队列中循环读取消息并把消息发送给handler
    messageQueue 是一个消息队列,用来存储消息。

    下面从源码的角度分析三者的关系:

    Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                }
                
            };
    handler.sendEmptyMessage(1);
    public Handler() {
            this(null, false);
    }
     1  public Handler(Callback callback, boolean async) {
     2         if (FIND_POTENTIAL_LEAKS) {
     3             final Class<? extends Handler> klass = getClass();
     4             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
     5                     (klass.getModifiers() & Modifier.STATIC) == 0) {
     6                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
     7                     klass.getCanonicalName());
     8             }
     9         }
    10 
    11         mLooper = Looper.myLooper();
    12         if (mLooper == null) {
    13             throw new RuntimeException(
    14                 "Can't create handler inside thread that has not called Looper.prepare()");
    15         }
    16         mQueue = mLooper.mQueue;
    17         mCallback = callback;
    18         mAsynchronous = async;
    19     }

    看到11行 就可以看到handler联系在一块了获取一个looper对象

    1     public static Looper myLooper() {
    2         return sThreadLocal.get();
    3     }

    下面看一下

    handler.sendEmptyMessage(1);
    里面做了什么东东!
    经过一路跟踪来到了
     1  public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
     2         MessageQueue queue = mQueue;
     3         if (queue == null) {
     4             RuntimeException e = new RuntimeException(
     5                     this + " sendMessageAtTime() called with no mQueue");
     6             Log.w("Looper", e.getMessage(), e);
     7             return false;
     8         }
     9         return enqueueMessage(queue, msg, uptimeMillis);
    10     }

    下面看看

    enqueueMessage(queue, msg, uptimeMillis) 做了什么

    1     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    2         msg.target = this;
    3         if (mAsynchronous) {
    4             msg.setAsynchronous(true);
    5         }
    6         return queue.enqueueMessage(msg, uptimeMillis);
    7     }

    看到第2行 其实就知道了 message跟handler关联起来了 msg.target 就是当前的handler实例。

    现在我们来看一下MessageQueue类中enqueueMessage()这个方法做了什么!其实想一下也知道肯定是往消息队列尾部添加一个消息

    下面我们看看该方法

     1  final boolean enqueueMessage(Message msg, long when) {
     2         if (msg.isInUse()) {
     3             throw new AndroidRuntimeException(msg + " This message is already in use.");
     4         }
     5         if (msg.target == null) {
     6             throw new AndroidRuntimeException("Message must have a target.");
     7         }
     8 
     9         boolean needWake;
    10         synchronized (this) {
    11             if (mQuiting) {
    12                 RuntimeException e = new RuntimeException(
    13                         msg.target + " sending message to a Handler on a dead thread");
    14                 Log.w("MessageQueue", e.getMessage(), e);
    15                 return false;
    16             }
    17 
    18             msg.when = when;
    19             Message p = mMessages;
    20             if (p == null || when == 0 || when < p.when) {
    21                 // New head, wake up the event queue if blocked.
    22                 msg.next = p;
    23                 mMessages = msg;
    24                 needWake = mBlocked;
    25             } else {
    26                 // Inserted within the middle of the queue.  Usually we don't have to wake
    27                 // up the event queue unless there is a barrier at the head of the queue
    28                 // and the message is the earliest asynchronous message in the queue.
    29                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
    30                 Message prev;
    31                 for (;;) {
    32                     prev = p;
    33                     p = p.next;
    34                     if (p == null || when < p.when) {
    35                         break;
    36                     }
    37                     if (needWake && p.isAsynchronous()) {
    38                         needWake = false;
    39                     }
    40                 }
    41                 msg.next = p; // invariant: p == prev.next
    42                 prev.next = msg;
    43             }
    44         }
    45         if (needWake) {
    46             nativeWake(mPtr);
    47         }
    48         return true;
    49     }

    我们很清楚的看到了 22和41行把这个消息next  就把这个消息添加到了消息队列中,我们把

    handler.sendEmptyMessage(1);分析完了 
    那么发送过消息后怎么又回调到 Handler的handleMessage方法中呢!
     public void handleMessage(Message msg) {
                    super.handleMessage(msg);
     }
    下面不得不说说looper了 
    看一下looper两个重要的方法
     1     public static void prepare() {
     2         prepare(true);
     3     }
     4 
     5     private static void prepare(boolean quitAllowed) {
     6         if (sThreadLocal.get() != null) {
     7             throw new RuntimeException("Only one Looper may be created per thread");
     8         }
     9         sThreadLocal.set(new Looper(quitAllowed));
    10     }
    11 
    12     private Looper(boolean quitAllowed) {
    13         mQueue = new MessageQueue(quitAllowed);
    14         mRun = true;
    15         mThread = Thread.currentThread();
    16     }

    执行prepare 方法就是新建一个looper对象和MessageQueue对象

    再看一下looper 的另外一个重要的方法

     1   public static void loop() {
     2         final Looper me = myLooper();
     3         if (me == null) {
     4             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
     5         }
     6         final MessageQueue queue = me.mQueue;
     7 
     8         // Make sure the identity of this thread is that of the local process,
     9         // and keep track of what that identity token actually is.
    10         Binder.clearCallingIdentity();
    11         final long ident = Binder.clearCallingIdentity();
    12 
    13         for (;;) {
    14             Message msg = queue.next(); // might block
    15             if (msg == null) {
    16                 // No message indicates that the message queue is quitting.
    17                 return;
    18             }
    19 
    20             // This must be in a local variable, in case a UI event sets the logger
    21             Printer logging = me.mLogging;
    22             if (logging != null) {
    23                 logging.println(">>>>> Dispatching to " + msg.target + " " +
    24                         msg.callback + ": " + msg.what);
    25             }
    26 
    27             msg.target.dispatchMessage(msg);
    28 
    29             if (logging != null) {
    30                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    31             }
    32 
    33             // Make sure that during the course of dispatching the
    34             // identity of the thread wasn't corrupted.
    35             final long newIdent = Binder.clearCallingIdentity();
    36             if (ident != newIdent) {
    37                 Log.wtf(TAG, "Thread identity changed from 0x"
    38                         + Long.toHexString(ident) + " to 0x"
    39                         + Long.toHexString(newIdent) + " while dispatching to "
    40                         + msg.target.getClass().getName() + " "
    41                         + msg.callback + " what=" + msg.what);
    42             }
    43 
    44             msg.recycle();
    45         }
    46     }

    我们看到这个是“死循环”,看27行

     msg.target.dispatchMessage(msg);
    其实就是调用的handler 的
    dispatchMessage()方法,看一下这个方法
     1     /**
     2      * Handle system messages here.
     3      */
     4     public void dispatchMessage(Message msg) {
     5         if (msg.callback != null) {
     6             handleCallback(msg);
     7         } else {
     8             if (mCallback != null) {
     9                 if (mCallback.handleMessage(msg)) {
    10                     return;
    11                 }
    12             }
    13             handleMessage(msg);
    14         }
    15     }

    呵呵终于看到 handleMessage方法回调了。大功告成。

    看到别人的博看上面讲 looper的prepare和loop()方法在activity初始化时就执行了,以前死活找不到在哪执行了

    今天终于找到了

     1  public static void main(String[] args) {
     2         SamplingProfilerIntegration.start();
     3 
     4         // CloseGuard defaults to true and can be quite spammy.  We
     5         // disable it here, but selectively enable it later (via
     6         // StrictMode) on debug builds, but using DropBox, not logs.
     7         CloseGuard.setEnabled(false);
     8 
     9         Environment.initForCurrentUser();
    10 
    11         // Set the reporter for event logging in libcore
    12         EventLogger.setReporter(new EventLoggingReporter());
    13 
    14         Process.setArgV0("<pre-initialized>");
    15 
    16         Looper.prepareMainLooper();
    17 
    18         ActivityThread thread = new ActivityThread();
    19         thread.attach(false);
    20 
    21         if (sMainThreadHandler == null) {
    22             sMainThreadHandler = thread.getHandler();
    23         }
    24 
    25         AsyncTask.init();
    26 
    27         if (false) {
    28             Looper.myLooper().setMessageLogging(new
    29                     LogPrinter(Log.DEBUG, "ActivityThread"));
    30         }
    31 
    32         Looper.loop();
    33 
    34         throw new RuntimeException("Main thread loop unexpectedly exited");
    35     

    尼玛原来就在16和32行 哎呦好像看到main方法了  这个代码在ActivityThread类中



     
  • 相关阅读:
    使用SignalR实现即时通讯功能
    SignalR入门篇
    Mongodb关闭开源许可感想
    RaspberryPi学习教程系列4(串口通信篇)
    RaspberryPi学习教程系列3(编程实验篇-双色LED实验)
    RaspberryPi学习教程系列1(系统安装篇)
    RaspberryPi学习教程系列2(编程前准备篇)
    关于Entity Framework,园里有非常多误人子弟的`
    Java多线程1:使用多线程的几种方式以及对比
    Django编写RESTful API(六):ViewSets和Routers
  • 原文地址:https://www.cnblogs.com/lihaolihao/p/4204511.html
Copyright © 2020-2023  润新知