在通常的軟件開發中,子線程中是不能更改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.