Toast,AlertDialog的誤解

在通常的軟件開發中,子線程中是不能更改UI主線程中建立的UI控件的。以前的理解是Toast也不能在子線程中建立。事實上並非這樣子的。html

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable(){
        @Override
        public void run() {
            // TODO Auto-generated method stub
            Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
        }}).start();
}

在Activity的onCreate中寫入以上代碼運行。LogCat中會抱錯java

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()android

 

不看這個錯誤信息第一反應確定是UI控件不能在子線程調用
事實上並非這樣的async

咱們能夠查看Toast的源碼ide

public Toast(Context context) {
        mContext = context;
        mTN = new TN();
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
    }
    
    /**
     * Show the view for the specified duration.
     */
public void show() {
    if (mNextView == null) {
        throw new RuntimeException("setView must have been called");
    }

    INotificationManager service = getService();
    String pkg = mContext.getPackageName();
    TN tn = mTN;
    tn.mNextView = mNextView;
    try {
        service.enqueueToast(pkg, tn, mDuration);
    } catch (RemoteException e) {
            // Empty
    }
}

看這個mTN = new TN();構造函數函數

final Handler mHandler = new Handler();    

Handler的構造函數oop

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

而Looper.myLooper()post

 /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

android中的子線程默認ThreadLocal中未設置Looper,全部會拋出這個異常,至於Looper是啥,能夠參考我另外一篇文章:http://www.cnblogs.com/cqcmdwym/archive/2013/05/12/3074138.htmlthis

解決方法spa

new Thread(new Runnable(){
    @Override
    public void run() {
        // TODO Auto-generated method stub
        Looper.prepare();
        Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
        Looper.loop();
}}).start();

或者在主線程中聲明一個Handler,而後在run方法中hanlder.post(new Runnable(){})一下。

一樣AlertDialog也是如此,他包含一個AlertController字段,其內部也須要建立一個Handler.

參考網址:http://www.oschina.net/question/163910_31439

相關文章
相關標籤/搜索