在工作线程中创建Toast,代码如下:
private void showToast() { new Thread() { public void run() { Looper.prepare(); Toast.makeText(ActivityA.this, "来自工作线程", Toast.LENGTH_SHORT).show(); Looper.loop(); } }.start(); }
如果不加Looper.prepare();则会出现以下异常:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
所以 在工作线程中创建Toast 须创建Looper对象。Looper.prepare();会创建当前线程的Looper对象和对应的MessageQueue(消息队列)
请参看Toast.java源码。
Toast.java 包含 这句代码:final Handler mHandler = new Handler();
mHandler是Toast的一个final类型的成员变量,在Handler的构造方法中有如下代码:
if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }
创建了Toast对象后,调用show()方法,把mShow这个Runnable添加到工作线程的消息队列中,
消息队列是在创建Looper对象的时候创建好的。
如代码:
final Runnable mShow = new Runnable() { public void run() { handleShow(); } }; public void show() { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.post(mShow); } /** * 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); }
此时调用Looper.loop(),从消息队列中取出消息,并执行。
主要源码:
/**
* 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 ...... msg.target.dispatchMessage(msg); ...... msg.recycle(); } } }
此时会调用:mShow的handleShow();
源码:
public void handleShow() {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; mWM = WindowManagerImpl.getDefault(); final int gravity = mGravity; mParams.gravity = gravity; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { mParams.horizontalWeight = 1.0f; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { mParams.verticalWeight = 1.0f; } mParams.x = mX; mParams.y = mY; mParams.verticalMargin = mVerticalMargin; mParams.horizontalMargin = mHorizontalMargin; if (mView.getParent() != null) { if (localLOGV) Log.v( TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this); mWM.addView(mView, mParams); } }
mWM.addView(mView, mParams);把Toast对应的view添加到当前Window中。
举一反三:
基于以上原理,可以实现这样的效果,拖动GridView里的ImageView元素,改变元素在GridView的位置。