`
czpsailer
  • 浏览: 10438 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

学习笔记:命令模式下的异步消息处理(Handler,Message,Looper,MessageQueue)

阅读更多
命令模式下的异步消息处理( Handler,Message,Looper,MessageQueue)


 
 
接受者:Handler,执行消息处理操作。
请求者:Looper,调用消息的的处理方法。
命令角色:Message,消息类。
客户端:Thread,创建消息并绑定Handler(接受者)。
 

 
命令角色:Message
  
    Class Overview:

    Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields    and an extra object field that allow you to not do allocations in many cases.

    消息包含了消息说明和任意的数据,消息能够被发送给Handler。消息对象包含2个额外的int类型字段(arg1,arg2)和一个额外的Object类型字段(obj),可以使用这写字段存放任意的信息(一般如果是简单的int类型数据存放在arg1和arg2这2个字段中就行了)。

   While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects. 
   一般使用静态方法Message.obtain()或Handler.obtainMessage()获取实例,这样的好处是获取的实例是来自一个循环使用的消息对象池。
    
MessageQueue
 
     这个类表示消息队列,一个消息队列与一个线程绑定。这个类内部是通过链表来实现队列的,根据消息的延迟执行的时间量来决定消息在队列中的位置,延迟执行的时间量越少的消息越靠前。
     MessageQueue.java 代码:
     消息入队列方法:
     final boolean enqueueMessage(Message msg, long when) { //参数when为消息的延迟时间量
        ........
        synchronized (this) {
            ................
            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
               //如果待入队列消息的延迟时间为0(立即执行)或比队列顶部消息的延迟时间少,则此待入队列消息放到队列顶部
                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;
    }  
   
    获取队列中的下一个消息:遍历消息队列,返回一个可以在当前时间处理的消息,如果找不到这样的一个消息,则阻塞当前线程,直到出现一个可以处理的消息为止。   

    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();
                }
            }
           
            //通过IdleHandler回调接口,提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
            // There was no message so we are going to wait...  but first,
            // if there are any idle handlers let them know.
            //调用IdleHandler回调接口执行
            //----------------start--------------
            boolean didIdle = false;
            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;
            }
            //----------------end--------------
           
            //获取当前队列顶部消息还有延迟多久才可以处理,使线程阻塞到那个时候为止
            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) {
                }
            }
        }
    }
 
   /**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     *  当线程进入阻塞前,执行此回调接口。这个接口提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
     */
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         * 当消息队列中没有可在当前时间处理的消息并且要进入阻塞等待出现可以处理的消息(比如:当前队列中所以的消息都是计划在当前时间之后执行的)时,调用此方法。
           返回true,使这个接口实例保持活动;false,这个接口实例将从接口实例类表中移除(这个接口列表是每次)。
         */
        boolean queueIdle();
    }
 
    请求者:Looper
 
    这个类用于为线程执行一个消息循环。Looper的实例与一个线程绑定,但是线程默认是没有Looper对象与其绑定的,可以通过在线程上调用Looper.prepare()绑定一个Looper对象到当前线程,这后调用Looper.loop()方法执行消息循环,直到循环被停止(遇到一个target=null的消息,就会退出当前消息循环)。
 
   public static final void loop() {
        Looper me = myLooper(); //获取与当前线程绑定的Looper对象
        MessageQueue queue = me.mQueue;
        while (true) {
            Message msg = queue.next(); // might block 从队列中获取一个消息,如果当前队列中没有可以立即处理的消息,则阻塞当前线程,直到出现一个可以处理的消息为止
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) { //遇到一个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(); //回收消息对象到消息对象池
            }
        }
    }   
 
    Looper通过一个本地线程变量来实现Looper实例与线程的绑定。
 
         private static final ThreadLocal sThreadLocal = new ThreadLocal();
 
    当在线程中调用prepare()时,判断当前线程是否已经有一个Looper对象与其绑定,如果有,这抛出一个异常;如果没有,则创建一个放了本地线程变量中。
 
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
   
    与线程绑定的消息队列也是在Looper实例创建时创建的。
 
    private Looper() {
        mQueue = new MessageQueue();
        .......
    }
    
    接受者:Handler

      对消息的发送和处理逻辑由一个Handler类提供。一个Handler的对象是与一个线程和线程的消息队列绑定,并将消息发送到这个消息队列,处理的也是这个消息队列中的消息。

      Class Overview:

     A Handler allows you to send and process Message  and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
    There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

    Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).

   When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.



以下代码演示了通过异步的消息由第三方线程控制View控件的移动.
 

 

 
package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.widget.AbsoluteLayout;
import android.widget.ImageView;

@SuppressWarnings("deprecation")
public class DemoActivity extends Activity {
	
	int i=0;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
	
	/**
	 * 在UI线程创建Handler,这样这个Handler就绑定了UI线程
	 * */
	Handler handler=new Handler(){
		public void handleMessage(Message msg){
    		/**
    		 * 每收到一个消息,就移动ImageView的位置
    		 * */
			ImageView imageView = (ImageView) findViewById(msg.arg1);
			AbsoluteLayout.LayoutParams params1 = new AbsoluteLayout.LayoutParams(
					imageView.getWidth(), imageView.getHeight(), 10,
					5 + msg.arg2);
			imageView.setLayoutParams(params1);
    	}
    };
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		/**
		 * 开启一个线程异步的发生消息给UI线程
		 * */
		new Thread(){
			public void run(){
				while (true) {
					try {
						Message message=handler.obtainMessage();
						message.arg1=R.id.img2;
						message.arg2=(i++);
						handler.sendMessage(message);
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		return super.onKeyDown(keyCode, event);
	}
}
 

序列图:

 

    
 
   
   

 

  • 大小: 21.5 KB
  • 大小: 14 KB
1
3
分享到:
评论
1 楼 gqdy365 2010-11-03  
不错的文章!

相关推荐

    Handler+Looper+MessageQueue

    在深入理解 Handler、Looper 和 MessageQueue 的工作原理后,我们可以利用它们实现更复杂的异步任务处理,如定时任务、延时操作以及多个消息的有序处理等。同时,它们也是 Android 中其他异步处理机制(如 AsyncTask...

    Android 异步处理 Handler+Looper+MessageQueue深入详解

    Handler、Looper和MessageQueue是Android异步处理机制中的核心组件,它们共同构建了一个消息传递系统,使得在不同线程间进行数据交换变得可能。下面我们将深入探讨这三个组件的工作原理及其在实际开发中的应用。 ...

    Handler Looper MessageQueue 源码解析

    在Android系统中,Handler、Looper和MessageQueue是实现线程间通信的核心组件,它们共同构建了一个消息处理机制。本文将深入解析这三者的源码,帮助你理解它们的工作原理,并教你如何手写一套自己的Handler系统。 ...

    Message,MessageQueue,Looper,Handler详解

    综上所述,Message、MessageQueue、Looper和Handler这四个组件共同构成了Android应用程序中处理消息的基本机制。通过它们之间的相互协作,使得应用程序能够在不同的线程间高效地传递和处理消息,从而实现了复杂的...

    handler与looper及messagequeue的简单总结

    在Android开发中,Handler、Looper和MessageQueue是用于实现线程间通信的关键组件,它们共同构建了一个消息处理机制。理解这三个概念以及它们之间的关系对于优化应用程序的性能和响应性至关重要。 Handler(处理器...

    Thread,Looper,Handler,Message,MessageQueue,MessagePool之间的关系

    在Android系统中,线程(Thread)、Looper、Handler、Message以及MessageQueue和MessagePool是实现异步消息处理机制的关键组件,它们共同构建了一个高效的事件驱动模型。这些组件的关系紧密,协同工作,使得Android...

    Android单线程模型中Message、Handler、Message Queue、Looper之间的关系---附实例源码

    Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理. 简单定义: 1、Message Queue(消息队列): 用来存放通过Handler发布的消息,通常...

    Android 之 Looper、MessageQueue、Handler 与消息循环

    - **消息处理**:Looper会不断地从MessageQueue中取出消息,并交给相应的Handler处理。 ##### 3. Handler Handler是用于发送消息和处理消息的关键类。每个Handler实例都与一个特定的线程及其消息队列关联。 - **...

    xamarin学习笔记A13(安卓Handler异步消息处理)

    1. Handler:是消息处理的核心,它定义了一个消息队列,并处理来自该队列的消息。通常,我们会在主线程中创建一个Handler实例,这样它就能接收到主线程的消息并进行处理。 2. Looper:每个线程都有一个消息循环,...

    Handler+Looper+MessageQueue+Message机制

    Message(消息):需要被传递的消息,其中包含了消息标识(what),消息处理数据和处理对象(arg1,arg2,obj),发送该消息的Handler对象(target)等,由MessageQueue统一列队,最终由Handler处理。 MessageQueue(消息...

    Handler和looper详解

    2. 消息队列管理:Looper可以管理消息队列,确保消息队列中的消息被正确地处理。 在Android系统中,每个线程都可以拥有一个Looper对象,并且可以通过Looper来实现消息处理机制。Looper的prepareMainLooper()方法...

    Android Handler Looper Message 使用示例

    在主线程即UI线程外,新建一个Looper线程,并用Messenger和Handler来处理message和posted runnable。程序中,在负线程中默认加了一个3s的线程等来,来帮助理解sent message和post runnable之间的同步机制。所以在按...

    Message,MessageQueue,Looper,Handler详解[归类].pdf

    【Looper】:Looper是线程中的消息循环器,负责从MessageQueue中取出Message并交给相应的Handler进行处理。Looper通过`loop()`方法执行一个无限循环,不断检查MessageQueue是否有新消息。主线程的Looper会持续运行,...

    管理MessageQueue的Looper使用

    首先,`Looper`是Android系统中一个用于处理消息循环的类,它在后台线程中不断检查消息队列`MessageQueue`,并将新消息分发给相应的`Handler`进行处理。通常,主线程(UI线程)已经有一个默认的`Looper`在运行,因此...

    Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系 - Hongyang -

    Handler的主要职责是发送Message到MessageQueue和处理由Looper分发的消息。通过`handleMessage(Message)`方法,Handler可以执行特定的操作,比如更新UI。同时,`post(Runnable)`方法也可用于延迟执行Runnable对象。...

    Android的消息处理机制--Message,MessageQueue

    4. **Looper循环**:Looper不断地从MessageQueue中取出Message并交给对应的Handler处理。 5. **处理消息**:Handler通过重写`handleMessage()`方法来处理消息。 #### 五、示例代码解析 为了更好地理解上述概念,...

    管理MessageQueue的Looper

    Looper的主要职责是循环地从MessageQueue中取出待处理的消息,并分发给相应的Handler进行处理。这一过程就是我们常说的“消息循环”。 MessageQueue,顾名思义,是一个消息队列,用于存储待处理的消息。这些消息...

    自定义Handler-Looper实现线程间通信

    在主线程(UI线程)中创建一个Handler实例后,我们可以在这个Handler中发送Message到Message Queue,然后由Looper取出并分发给相应的Handler进行处理。这样,即使Message是在其他线程中生成的,它们也能在正确的线程...

    活用Android的Message Queue

    - Handler对象可以与Looper配合,将消息放入Message Queue,或从Queue中取出消息进行处理。 - Handler对象可以跨线程传递,允许其他线程向指定线程发送消息。 - 消息队列中的消息只能由所属线程的对象处理,确保...

    Android的消息处理机制--Looper,Handler

    `Handler`提供了异步消息处理机制,可以在不阻塞当前线程的情况下发送消息。`Handler`有四个构造函数,其中默认的构造函数将`Handler`与当前线程的`Looper`和`MessageQueue`关联。用户通常需要重写`handleMessage`...

Global site tag (gtag.js) - Google Analytics