在工作线程中创建Toast

阅读更多

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

你可能感兴趣的:(android,Toast)