在工作线程中创建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的位置。