欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android Looper HandlerThread MessageQueue Handler Message(完善中......)

程序员文章站 2022-07-14 17:05:18
...


ActivityThread.java 的 main主函数启动入口

public static final void main(String[] args) { Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); Looper.loop(); if (Process.supportsProcesses()) { throw new RuntimeException("Main thread loop unexpectedly exited"); } thread.detach(); String name; if (thread.mInitialApplication != null) name = thread.mInitialApplication.getPackageName(); else name = "<unknown>"; Log.i(TAG, "Main thread of " + name + " is now exiting"); }Looper.java

从prepareMainLooper方法的注释可以理解,初始化当期线程,而looper和一个线程关联,并且提供了主线程looper对象的对外接口

/** Initialize the current thread as a looper, marking it as an application's main * looper. The main looper for your application is created by the Android environment, * so you should never need to call this function yourself. * {@link #prepare()} */ public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } } private synchronized static void setMainLooper(Looper looper) { mMainLooper = looper; } /** Returns the application's main looper, which lives in the main thread of the application. */ public synchronized static final Looper getMainLooper() { return mMainLooper; } 初始化当前线程,之后把一个初始化的Looper关联线程,在Looper初始化的时候做了一些操作就是初始化了一个消息队列MessageQueue即通过Looper来管理MessageQueue,通过调用Looper.myLooper()可以获得当前线程的Looper对象,但是Looper的构造函数是私有的,外界无法直接实例化之;要实例化,只有通过Looper::prepare()

// sThreadLocal.get() will return null unless you've called prepare(). private static final ThreadLocal sThreadLocal = new ThreadLocal(); /** 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()); } private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }
looper里面的消息队列进行循环机制,执行消息队列里面的一个个消息,注意msg.target是个Handler对象
/** * 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; 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); msg.recycle(); } } }

轮循中开始处理系统的一个个消息,两种情况一种正常消息处理,一种回掉处理;其中

handleMessage(msg)为需要用户自己继承Handler来覆盖此方法作为用户需要执行的任务。

/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }

理解下HandlerThread,你会发现HandlerThread继承Thread,HandlerThread::run()里面调用了Looper的初始化prepare();和looper()。

public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); Process.setThreadPriority(mPriority); notifyAll(); } onLooperPrepared(); Looper.loop(); mTid = -1; }

理解Handler,从下面的Handler构造函数可以了解Handler的构造是需要Looper对象的,没有参数Looper的构造函数是用当前线程的looper对象;而当然你也可以通过HandlerThread施行run后就有了looper对象,通过对外的接口getLooper()可以获取此Looper对象,MessageQueue在looper中是一个属性,所以你需要记忆这个。

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; } /** * Use the provided queue instead of the default one. */ public Handler(Looper looper) { mLooper = looper; mQueue = looper.mQueue; mCallback = null; }

说明:对于以上的理解我在最后会有实例来验证说明,到这里我们的疑问是现在我们想知道 消息是怎么封装的,消息是怎么放入消息队列的?

消息的入消息队列

/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * / public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * / public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; 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.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } 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; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }


通过上面的理解,用实例来验证上面的理解,下面是我以前项目中写的代码。

实例一:在一个activity耗时的操作方法中自己起了一个线程

Thread th = new Thread() { public void run() { Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { public void run() { Toast.makeText(MailView.this, "�ʼ����ͳɹ�", Toast.LENGTH_LONG).show(); } } ) } } th.start();

实例二:Service中,这里注意下,Message的对象创建Message::obtain(),这个对象也可以是Handler的obtainMessage()来创建。

private final Handler handler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MSG_TIMER: mWorker = new HandlerThread("MyWorker"); mWorker.start(); mWorkerHandler = new Handler(mWorker.getLooper()); mWorkerHandler.postDelayed(new MessageReceiveTask(), SECONDRESOLVERMESSAGE); break; } } }; public void onCreate() { super.onCreate(); Log.i(Constant.TAG_INFO, "StartService*****************************************"); Message msgget = Message.obtain(); msgget.what = MSG_TIMER; handler.sendMessageDelayed(msgget, SECONDRESOLVERMESSAGELONG); }
 class MessageReceiveTask implements Runnable {
		public void run() {
			try {
				loadInitInboxData();
			} catch (Exception e) {
				Log.i(Constant.TAG_EXCEPTION, "MessageReceiveTask  :  " + e);
			}
			mWorkerHandler.postDelayed(this, SECONDRESOLVERMESSAGE);
		}
	}


从上面我写的代码可以看到发送有两种方式,sendMessage(m)和postDelayed(r)两种,我列出源码

/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } /** * Causes the Runnable r to be added to the message queue, to be run * after the specified amount of time elapses. * The runnable will be run on the thread to which this handler * is attached. * */ public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } /** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * The runnable will be run on the thread to which this handler is attached. * @see android.os.SystemClock#uptimeMillis */ public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } /** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. */ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; } 下班了,。。。。。。上面是一个流程的了解,下面我们需要对细节的了解,这个有待继续。

下面是message的创建,请注意这里,先从池中取出,需要明白下面是个单向链表的形式,从注释中可以了解到:// sometimes we store linked lists of these things
Message next;如果在池中没有就从新new一个对象。

/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (mPoolSync) { if (mPool != null) { Message m = mPool; mPool = m.next; m.next = null; return m; } } return new Message(); }
注意message要是用完后,需要回收放入池中

/** * Return a Message instance to the global pool. You MUST NOT touch * the Message after calling this function -- it has effectively been * freed. */ public void recycle() { synchronized (mPoolSync) { if (mPoolSize < MAX_POOL_SIZE) { clearForRecycle(); next = mPool; mPool = this; } } }

从// might block这个注释说开来,

public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; 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); msg.recycle(); } } } 继续说明消息是怎么取的

final Message next() { boolean tryIdle = true; while (true) { long now; Object[] idlers = null; // Try to retrieve the next message, returning if found. synchronized (this) { now = SystemClock.uptimeMillis(); Message msg = pullNextLocked(now); 具体的通过单向链表方式来操作的,看这个方法的具体内容就明白了。 if (msg != null) return msg; if (tryIdle && mIdleHandlers.size() > 0) { idlers = mIdleHandlers.toArray(); } } // There was no message so we are going to wait... but first, // if there are any idle handlers let them know. boolean didIdle = false;//no idle if (idlers != null) { for (Object idler : idlers) { boolean keep = false; try { didIdle = true; keep = ((IdleHandler)idler).queueIdle(); } catch (Throwable t) { Log.e("MessageQueue", "IdleHandler threw exception", t); RuntimeInit.crash("MessageQueue", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } } // While calling an idle handler, a new message could have been // delivered... so go back and look again for a pending message. if (didIdle) { tryIdle = false; continue; } synchronized (this) { // No messages, nobody to tell about it... time to wait! try { if (mMessages != null) { if (mMessages.when-now > 0) { Binder.flushPendingCommands(); this.wait(mMessages.when-now); 这里需要说明的是堵塞等待一个特定的时间 } } else { Binder.flushPendingCommands(); this.wait(); 堵塞 ,期待唤醒 } } catch (InterruptedException e) { } } } } 下面是通过比较当前系统的真实时间long来和消息的message的when时间值来比较,如果当前时间大于或等于消息时间,就把当前节点取出来,把下一个赋值给当前节点。
    final Message pullNextLocked(long now) {
        Message msg = mMessages;
        if (msg != null) {
            if (now >= msg.when) {
                mMessages = msg.next;
                if (Config.LOGV) Log.v(
                    "MessageQueue", "Returning message: " + msg);
                return msg;
            }
        }

        return null;
    }

消息的入对列也是单向列表式的操作

final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } 上面的msg.when!=0是因为之前这个方法被调用前没有被赋值过,如果被赋值过,则说明已经被使用中了。 if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } 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; 把当前的节点赋值给传进来的message的下一个,而下面一句则是把传进来的message作为最新的当前节点。 mMessages = msg; 下面一句是唤醒,通过上面的判断有消息入队,则进行唤醒来进行处理。 this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
现在你开朗了吗?。。。。。。