寫代碼的時候碰到android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.這個異常。
異常的意思是說只有創建這個view的線程才能操作這個view,普通會認為是將view創建在非UI線程中才會出現這個錯誤。
可是在我代碼中將view創建在UI線程中也會出現這個錯誤
下面是我出錯的代碼:
AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>(){ ProgressDialog progressDialog; @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = new ProgressDialog(getContext()); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setMessage("請稍后..."); progressDialog.show(); } @Override protected Void doInBackground(Void... params) { //耗時操作... return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); progressDialog.dismiss(); } }; myTask.execute();
如上,將progressDialog創建在UI進程中還會出現以上錯誤。
最后在仔細檢查時,發現在doInBackground方法里調用了view.invalidate();這個方法。
調用這個方法會調用view的onDraw();方法,從而引起窗口重繪,自然原本的UI進程也被破壞。等到執行完doInBackground后,再調用onPostExecute這個方法執行progressDialog.dismiss();時已經找不到原本創建它的UI進程,自然就會報android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.這個錯誤了。
另外, 一般引起invalidate()操作的函數如下:
1、直接調用invalidate()方法,請求重新draw(),但只會繪制調用者本身。
2、setSelection()方法 :請求重新draw(),但只會繪制調用者本身。
3、setVisibility()方法 : 當View可視狀態在INVISIBLE轉換VISIBLE時,會間接調用invalidate()方法,
繼而繪制該View。
4 、setEnabled()方法 : 請求重新draw(),但不會重新繪制任何視圖包括該調用者本身。
查閱這個異常的相關信息時,發現另外一種情況也可能導致這個異常:
http://my.oschina.net/qixiaobo025/blog/195396