在通常的软件开发中,子线程中是不能更改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.