在一般的软件开发中,子线程中是不能更改UI主线程中创建的UI控件的。之前的理解是Toast也不能在子线程中创建。事实上并不是这样子的。
@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.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
不看这个错误信息第一反应肯定是UI控件不能在子线程调用
事实上并不是这样的
我们可以查看Toast的源码
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的构造函数
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()
/**
* 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.html
解决方法
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.