写代码的时候碰到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