Android中Looper、Handler、MessageQueue源码不完全分析

先来看一个例子:

public class MainActivity extends Activity {
	
	private TextView textView;
	private Button button;
	private Handler handler;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button) findViewById(R.id.button_id);
        button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				System.out.println("Clicked .. "+ Thread.currentThread().getName());
				Bundle bundle = new Bundle();
				bundle.putInt("age", 23);
				bundle.putString("name", "han");
				Message msg = handler.obtainMessage();
				msg.setData(bundle);
				handler.sendMessage(msg);
			}
		});
        
        WorkerThread wt = new WorkerThread();
        wt.start();
        
    }
    
    class WorkerThread extends Thread{
    	@Override
    	public void run() {
    		Looper.prepare();
    		handler = new Handler(){
    			@Override
    			public void handleMessage(Message msg) {
    				System.out.println("WorkerThread name : "+Thread.currentThread().getName());
    				System.out.println("在"+Thread.currentThread().getName()+"线程中进行处理费时的操作..");
    				System.out.println("age : " + msg.getData().getInt("age") + " name : " + msg.getData().getString("name"));
    			}
    		};
    		Looper.loop();
    	}
    }
}
下面是运行的效果:

System.out: Clicked .. main
System.out: WorkerThread name : Thread-4872
System.out: 在Thread-4872线程中进行处理费时的操作..
System.out: age : 23 name : han


OK,下面切入正题!


在android开发中,handler主要是为了实现线程(MainThread、WorkerThread)间的消息传递,google将其设计的很巧妙,刚开始接触总是感觉云里雾里,下面通过源代码窥探其中的原理,如有错误不妥,还望大神指正。

先看我们程序中使用handler的一般写法(在Looper.java源代码中也有):

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();
      }
}
 

以下是Looper.java的部分源代码,仅贴出对理解有帮助的行:

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;
    final MessageQueue mQueue;
    final Thread mThread;

    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final 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();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // 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);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.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(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.recycleUnchecked();
        }
    }

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

    public static MessageQueue myQueue() {
        return myLooper().mQueue;
    }
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
}

下面再贴出Handler.java的部分源代码:

public class Handler {
    public Handler() {
        this(null, false);
    }
    public Handler(Callback callback, boolean async) {

	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 = callback;
        mAsynchronous = async;
    }
    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
}

现在我们从前往后梳理,其实这中间主要用到一个ThreadLocal类,它通过set、get方法设置和得到与当前线程相关的局部变量,此处为Looper,不懂的童鞋请前往这里。通过ThreadLocal类,以及Looper、Handler中成员变量的赋值,建立了Looper和Handler的联系。

Looper.prepare();

在Looper.java中,我们看到,在调用prepare()方法时,创建了一个Looper对象(创建Looper对象时创建了MessageQueue对象,并将其放到成员变量mQueue中),并将该对象放到ThreadLocal(即当前线程中有一个Looper对象)中。

mHandler = new Handler()

在Handler.java中,我们看到,构造方法在调用时,调用Looper.myLooper()方法,得到当前线程中的Looper对象,赋值给Handler的成员变量mLooper,同时从当前线程中的Looper(即Handler.mLooper)中取得MessageQueue(即Looper.mQueue),赋值给Handler的成员变量mQueue。至此,Looper和Handler的联系便已经建立起来了。先总结下:一个Looper对象对应一个线程,同时也对应一个Handler,Looper和Handler对应的MessageQueue是同一个。

接下来,Looper.loop();

从源代码中我们可以看到,调用myLooper()方法,得到当前线程中Looper对象,进而取得与Looper对应的MessageQueue对象,赋值给queue,进入for循环,从消息队列中取得待处理的Message对象msg(这个过程可能会被阻塞),接下来msg.target.dispatchMessage(msg),在这里,msg.target是个什么东西呢?在程序中,我们一般会这么写:

Message msg = handler.obtainMessage();

handler.sendMessage(msg);

首先,我们先看下Hander.obtainMessage()方法:

public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

可以看到,这里调用了Message.obtain(this)方法,而this指的是掉用该方法的对象,按照上述我们一般的写法,即handler.再看Message.obtain(Handler h)方法:

public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
    }

public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

Message类的成员变量我们此时来看下:

public final class Message implements Parcelable {
    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    public int sendingUid = -1;
    static final int FLAG_IN_USE = 1 << 0;
    static final int FLAG_ASYNCHRONOUS = 1 << 1;
    static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    int flags;
    long when;  
    Bundle data; 
    Handler target;    
    Runnable callback;    
    Message next;
    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
    private static boolean gCheckRecycle = true;

此处重点注意下target成员变量,可以看到该成员变量是一个Handler类型的,所以msg.target指的就是生成该消息对象的Handler对象。再看Handler.dispatchMessage(Message msg)方法:

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

该方法中handleMessage方法就是需要我们来写的逻辑代码。


另外这篇文章写得也挺不错,大家可以参考下。http://blog.csdn.net/guolin_blog/article/details/9991569


以下附上我练习的代码:

Ⅰ、演示Handler初步认识

public class MainActivity extends Activity {

	private Button button;
	private Handler handler;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button) findViewById(R.id.button);    
        
        handler = new FirstHandler();
        
        button.setOnClickListener(new OnClickListener() {
			
        	@Override
			public void onClick(View v) {
        		Message msg = handler.obtainMessage();
        		msg.what = 88;
				handler.sendMessage(msg);
				//上面一行代码将消息对象放置到消息队列中
				//1、Looper将会从消息队列中将消息对象取出
				//2、Looper将会找到与消息对象对应的Handler对象
				//3、Looper将会调用handler对象的hanleMessage(Message msg)方法,用于处理消息对象
			}
		});
        
    }
    
    class FirstHandler extends Handler {
    	@Override
    	public void handleMessage(Message msg) {
    		System.out.println("what : " + msg.what);
    	}
    }
}

Ⅱ、演示在WorkerThread处理业务并在MainThread更新UI

public class MainActivity extends Activity {

	private Button button;
	private Handler handler;
	private TextView textView;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        handler = new MyHandler();
        textView = (TextView) findViewById(R.id.textView);
        button = (Button) findViewById(R.id.button);    
        button.setOnClickListener(new OnClickListener() {
			
        	@Override
			public void onClick(View v) {
        		Thread wt = new WorkerThread();
        		wt.start();
			}
		});
        
    }
    
    class WorkerThread extends Thread{
    	@Override
    	public void run() {
    		try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		Message msg = handler.obtainMessage();
    		msg.obj = "data from the Internet...";
    		handler.sendMessage(msg);
    	}
    }
    
    class MyHandler extends Handler {
    	@Override
    	public void handleMessage(Message msg) {
    		String s = (String) msg.obj;
    		textView.setText(s);
    	}
    }
}

Ⅲ、从MainThread向WorkerThread中发送消息

public class MainActivity extends Activity {

	private Button button;
	private Handler handler;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button) findViewById(R.id.button);    
        button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Message msg = handler.obtainMessage();
				System.out.println("onClick:"+Thread.currentThread().getName());
				handler.sendMessage(msg);
			}
		});
        
        Thread thread = new WorkerThread();
        thread.start();
    }
    
    class WorkerThread extends Thread{
    	@Override
    	public void run() {
    		Looper.prepare();
    		handler = new Handler(){
    			@Override
    			public void handleMessage(Message msg) {
    				System.out.println("WorkerThread:"+Thread.currentThread().getName());
    				System.out.println("消息来啦...");
    			}
    		};
    		Looper.loop();
    	}
    }
}


下面是post方法的使用:

public class MainActivity extends Activity {

	private TextView textView;
	private Handler handler;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
         textView = (TextView)findViewById(R.id.textView);
         
         handler = new Handler();
         
         new Thread(){
        	 public void run() {
        		 try {
					Thread.sleep(1000);
					handler.post(new Runnable(){
	        			public void run() {
	        				System.out.println(Thread.currentThread().getName());
	        				textView.setText("update Thread...");
	        			}; 
	        		 });
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		 
        	 };
         }.start();
    }
    
}
更新UI,输出结果,打印的线程名字是 main!是不是很诧异.我们看下post方法源代码:

Handler.java

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
看到这里,结合上面的dispatchMessage方法,

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
此处直接执行了handleCallback(msg)方法.

private static void handleCallback(Message message) {
        message.callback.run();
    }

message.callback正是我们定义的Runnable对象,直接调用了它的run()方法.由于处理该方法的Looper是在MainThread中生成的,所以虽然从代码上看启用了一个新线程,但还是在UIThread中执行的,所以会进行更新UI的操作,不会报ANR错误.

另外一个例子:

public class HandlerActivity extends Activity {  
         /** Called when the activity is first created. */  
         @Override  
         public void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
           setContentView(R.layout.main);  
           Button b1 = (Button)findViewById(R.id.button1);  
           Button b2 = (Button)findViewById(R.id.button2);  
           b1.setOnClickListener(new OnClickListener() {  
               @Override  
               public void onClick(View v) {  
                   //立即把线程加入消息队列中  
                   handler.post(r);  
               }  
           });  
           b2.setOnClickListener(new OnClickListener() {  
               @Override  
               public void onClick(View v) {  
                   //停止线程  
                   handler.removeCallbacks(r);  
               }  
           });  
         }  
         Handler handler = new Handler();  
   /**
        *该方法的内部类将在handler.sendMessage(msg)后执行
            Handler handler = new Handler(){
           @Override
           public void handleMessage(Message msg) {
               System.out.println("msg:"+msg.arg1);
           }
           };
       */  
         Runnable r = new Runnable() {  
           @Override  
           public void run() {  
               System.out.println("sysout Thread");  
               //得到一个消息对象,Message类是有Android系统  
               Message msg = handler.obtainMessage();  
               //将msg对象arg1参数设置为122,用arg1和arg2传递消息  
               //优点是系统资源消耗较小  
               msg.arg1 = 122;  
               //将消息加入到另外一个消息队列中去  
               handler.sendMessage(msg);  
               //3000毫秒后加入线程到消息队列中  
               handler.postDelayed(r, 3000);  
           }  
         };  
   }

以下再演示一个postDelayed()的例子:

public class MainActivity extends Activity {

	private TextView textView;
	private ImageView imgView;
	private int index;
	private Handler handler = new Handler();
    int[] imgs = {R.drawable.p1,R.drawable.p2,R.drawable.p3}; 	
	class MyRunnable implements Runnable{
		@Override
		public void run() {
			index++;
			index = index%3;
			imgView.setImageResource(imgs[index]);
			handler.postDelayed(this, 1000);
		}
	}
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.textView);
     	imgView = (ImageView) findViewById(R.id.imageView);
     	//new Thread(new MyRunnable()).start();
        handler.post(new MyRunnable()); 
    }
}
程序启动后,每隔一秒会更新图片。

下面是Handler的另一种构造方法的事例:

public class MainActivity extends Activity {

	private Button button;
	
	private Handler handler = new Handler(new Callback() {
		@Override
		public boolean handleMessage(Message arg0) {
			Toast.makeText(getApplicationContext(), ""+1, 1).show();
			<strong>return true;</strong>
		}
	}){
		public void handleMessage(Message msg) {
			Toast.makeText(getApplicationContext(), ""+2, 1).show();
		};
	};
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     	button = (Button) findViewById(R.id.button);
     	button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				handler.sendEmptyMessage(1);
			}
		});
    }
}
当黑体部分返回true时,不会执行Handler的 public void handleMessage(Message msg)方法,当黑体部分返回假时,才会执行我们重写的handler的handleMessage方法。让我们看下源代码。Callback其实是Handler的一个内部接口:

Handler$Callback.class

public interface Callback {
        public boolean handleMessage(Message msg);
    }
再结合上面提到的Handler的构造方法:
public Handler(Callback callback) {
        this(callback, false);
    }
public Handler(Callback callback, boolean async) {
        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 = callback;
        mAsynchronous = async;
    }
还有

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
可以看到其中的玄机。所以,我们可以在构造Handler时重写Callback的handleMessage方法来起到一个过滤的作用,对符合条件的消息返回false进行处理。

下面再来看看HandlerThread的用法。例子:
public class MainActivity extends Activity {
	
	private TextView text;
	private Handler handler;
	private HandlerThread thread;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		text = new TextView(this);
		text.setText("handler Thread...");
		setContentView(text);
		thread = new HandlerThread("ThreadName...");
		thread.start();
		handler = new Handler(thread.getLooper()){
			@Override
			public void handleMessage(Message msg) {
				System.out.println("当前线程名称:"+Thread.currentThread().getName());
			}
		};
		handler.sendEmptyMessage(1);
	}
}

程序运行后,输出:当前线程名称:ThreadName...

HandlerThread就是一个线程,它继承Thread类,我们看看它的run()方法:

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

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
利用HandlerThread类可以更好的帮助我们实现线程的操作。


补充一点,handler.sendMessage()将Message发送到消息队列中,其中的handler就要将来处理Message的Handler,和Message.sendToTarget一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值