|
在一般的軟件開發中,子線程中是不能更改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.tshopping.com.tw/thread-257623-1-1.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.
但如果有用 Thread.isAlive() 就不能用
線程會跟AlertDialog產生迴圈卡住
參考網址:http://www.oschina.net/question/163910_31439
|
|