TShopping

 找回密碼
 註冊
搜索
查看: 1183|回復: 0
打印 上一主題 下一主題

[教學] Thread 對於Toast,AlertDialog的問題

[複製鏈接]
跳轉到指定樓層
1#
發表於 2017-8-24 15:17:08 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
 
Push to Facebook
在一般的軟件開發中,子線程中是不能更改UI主線程中創建的UI控件的。之前的理解是Toast也不能在子線程中創建。事實上並不是這樣子的。

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3.     super.onCreate(savedInstanceState);
  4.     setContentView(R.layout.activity_main);
  5.     new Thread(new Runnable(){
  6.         @Override
  7.         public void run() {
  8.             // TODO Auto-generated method stub
  9.             Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
  10.         }}).start();
  11. }
複製代碼

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

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


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

我們可以查看Toast的源碼

  1. public Toast(Context context) {
  2.         mContext = context;
  3.         mTN = new TN();
  4.         mTN.mY = context.getResources().getDimensionPixelSize(
  5.                 com.android.internal.R.dimen.toast_y_offset);
  6.     }
  7.    
  8.     /**
  9.      * Show the view for the specified duration.
  10.      */
  11. public void show() {
  12.     if (mNextView == null) {
  13.         throw new RuntimeException("setView must have been called");
  14.     }

  15.     INotificationManager service = getService();
  16.     String pkg = mContext.getPackageName();
  17.     TN tn = mTN;
  18.     tn.mNextView = mNextView;
  19.     try {
  20.         service.enqueueToast(pkg, tn, mDuration);
  21.     } catch (RemoteException e) {
  22.             // Empty
  23.     }
  24. }
複製代碼


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

  1. final Handler mHandler = new Handler();  
複製代碼

Handler的構造函數

  1. public Handler(Callback callback, boolean async) {
  2.        ...
  3.         mLooper = Looper.myLooper();
  4.         if (mLooper == null) {
  5.             throw new RuntimeException(
  6.                 "Can't create handler inside thread that has not called Looper.prepare()");
  7.         }
  8.        ...
  9.     }
複製代碼

而Looper.myLooper()

  1. /**
  2.      * Return the Looper object associated with the current thread.  Returns
  3.      * null if the calling thread is not associated with a Looper.
  4.      */
  5.     public static Looper myLooper() {
  6.         return sThreadLocal.get();
  7.     }
複製代碼

android中的子線程默認ThreadLocal中未設置Looper,所有會拋出這個異常,至於Looper是啥,可以參考我另一篇文章:http://www.tshopping.com.tw/thread-257623-1-1.html

解決方法

  1. new Thread(new Runnable(){
  2.     @Override
  3.     public void run() {
  4.         // TODO Auto-generated method stub
  5.         Looper.prepare();
  6.         Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
  7.         Looper.loop();
  8. }}).start();
複製代碼

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

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

但如果有用 Thread.isAlive() 就不能用

線程會跟AlertDialog產生迴圈卡住


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

 

臉書網友討論
*滑块验证:
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-4-27 02:31 , Processed in 0.055920 second(s), 22 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表