andorid程序UI线程下开启子线程闪退错误解决
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original
運行時報 android.view.ViewRootImpl$CalledFromWrongThreadException:錯誤
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
原因操作阻塞了UI線程 或者 在工作線程中操作了UI元素
知道原因就好解決了:
在工作線程中更新UI的三種方法:
???????1. Activity.runOnUiThread(Runnable) ;
???????2. Handler(sendMessage(Message) or post(Runnable));
???????3. AsyncTask ;
出現種錯誤一般是在使用第三方方法時,沒有注意是不是UI線程 所導致的!個人比較喜歡 runOnUiThread() 來解決。
?
當應用程序啟動,創建了一個叫“main”的線程,用于管理UI相關,又叫UI線程。其他線程叫工作線程(Work Thread)。
Single Thread Model
?
- 一個組件的創建并不會新建一個線程,他們的創建都在UI線程中進行,包括他們的回調方法,如onKeyDown()。
- 當在UI線程中進行某些耗時的操作時,將會阻塞UI線程,一般阻塞超過5秒就會顯示一個ANR對話框。
- UI線程是非線程安全的,所以,不能在工作線程中操作UI元素。
?
兩個原則
- Do not block the UI thread (不要阻塞UI線程)
- Do not access the Android UI toolkit from outside the UI thread (不要在工作線程中操作UI元素)
?
在工作線程更新UI方法
- Activity.runOnUiThread(Runnable)
- Handler
- sendMessage(Message)
- post(Runnable)
- AsyncTask
- execute()
- doInBackground()
- onPostExecute()
?
例子程序
- HandlerActivity01
- 在工作線程中進行UI操作。
- HandlerActivity02
- Handler的兩個重要方法:sendMessage和post。
- HandlerActivity03
- 官方推薦最佳方法。
?
HandlerActivity01主要代碼:
Java代碼???
- btnEnd.setOnClickListener(new?View.OnClickListener()?{??
- ??????
- ????@Override??
- ????public?void?onClick(View?v)?{??
- ????????new?Thread(new?Runnable()?{??
- ??
- ????????????@Override??
- ????????????public?void?run()??
- ????????????{??
- ????????????????//在新建的線程(工作線程)中改變Button的文字??
- ????????????????btnEnd.setText("Text?Changed?in?Sub?Thread");??
- ????????????}??
- ??????????????
- ????????}).start();??
- ????}??
- });??
- android.view.ViewRootImpl$CalledFromWrongThreadException:?Only?the?original?thread?that?created?a?view?hierarchy?can?touch?its?views.???
- public?class?HandlerActivity02?extends?Activity??
- {??
- ??
- ????private?int?title?=?0;??
- ????Button?btnStart,btnEnd;??
- ??
- ????private?Handler?mHandler?=?new?Handler()??
- ????{??
- ????????public?void?handleMessage(Message?msg)??
- ????????{??
- ????????????//更新UI??
- ????????????switch?(msg.what)??
- ????????????{??
- ????????????????case?1:??
- ????????????????????updateTitle();??
- ????????????????????break;??
- ????????????}??
- ????????};??
- ????};??
- ??????
- ????public?void?onCreate(Bundle?savedInstanceState)??
- ????{??
- ????????super.onCreate(savedInstanceState);??
- ????????setContentView(R.layout.main);??
- ??????????
- ????????btnStart?=?(Button)findViewById(R.id.start);??
- ????????btnEnd?=?(Button)findViewById(R.id.end);??
- ????????//新啟動一個線程,進行耗時操作??
- ????????Timer?timer?=?new?Timer();??
- ????????//每六秒執行一次MyTask的run方法??
- ????????timer.scheduleAtFixedRate(new?MyTask(this),?1,?6000);??
- ????}??
- ??
- ????private?class?MyTask?extends?TimerTask??
- ????{??
- ????????private?Activity?context;??
- ????????MyTask(Activity?context)??
- ????????{??
- ????????????this.context?=?context;??
- ????????}??
- ??????????
- ????????@Override??
- ????????public?void?run()??
- ????????{??
- ????????????//耗時操作略....???
- ??????????????
- ????????????//更新UI方法??1??
- ????????????Message?message?=?new?Message();??
- ????????????message.what?=?1;??
- ????????????mHandler.sendMessage(message);??
- ??????????????
- ????????????//更新UI方法??2??
- ????????????mHandler.post(updateThread);??
- ??????????????
- ????????????//更新UI方法??3??
- ????????????context.runOnUiThread(updateThread);??
- ????????}??
- ????}??
- ??
- ????public?void?updateTitle()??
- ????{??
- ????????setTitle("Welcome?to?Mr?Wei's?blog?"?+?title);??
- ????????title++;??
- ????}??
- ??????
- ????Runnable?updateThread?=?new?Runnable()???
- ????{??
- ??
- ????????@Override??
- ????????public?void?run()??
- ????????{??
- ????????????//更新UI??
- ????????????btnStart.setText(String.valueOf(title));??
- ????????????btnEnd.setText(String.valueOf(title));??
- ????????}??
- ??????????
- ????};??
- }??
- public?class?HandlerActivity03?extends?Activity??
- {??
- ????Button?btnStart;??
- ????@Override??
- ????protected?void?onCreate(Bundle?savedInstanceState)??
- ????{??
- ????????//?TODO?Auto-generated?method?stub??
- ????????super.onCreate(savedInstanceState);??
- ????????setContentView(R.layout.main);??
- ??????????
- ????????btnStart?=?(Button)findViewById(R.id.start);??
- ????????btnStart.setOnClickListener(new?View.OnClickListener()?{??
- ??????????????
- ????????????@Override??
- ????????????public?void?onClick(View?v)?{??
- ????????????????//開始執行AsyncTask,并傳入某些數據??
- ????????????????new?LongTimeTask().execute("New?Text");??
- ????????????}??
- ????????});??
- ????}??
- ??????
- ????private?class?LongTimeTask?extends?AsyncTask??
- ????{??
- ??
- ????????@Override??
- ????????protected?String?doInBackground(String...?params)??
- ????????{??
- ????????????try??
- ????????????{??
- ????????????????//線程睡眠5秒,模擬耗時操作,這里面的內容Android系統會自動為你啟動一個新的線程執行??
- ????????????????Thread.sleep(5000);??
- ????????????}??
- ????????????catch?(InterruptedException?e)??
- ????????????{??
- ????????????????e.printStackTrace();??
- ????????????}??
- ????????????return?params[0];??
- ????????}??
- ??
- ????????@Override??
- ????????protected?void?onPostExecute(String?result)??
- ????????{??
- ????????????//更新UI的操作,這里面的內容是在UI線程里面執行的??
- ????????????btnStart.setText(result);??
- ????????}??
- ??????????
- ????}??
- ??
- }??
?
?這是一種錯誤的做法,運行程序,會報錯誤:
Java代碼???
?
?
?
?
?
?HandlerActivity02主要代碼:
Java代碼???
?這里有個容易出錯的地方,在更新UI方法2和3中,我們傳入的參數是一個Runnable對象,一般認為這就會啟動一個新的線程,而且常有人在這個Runnable對象的run方法中進行耗時操作??催^這塊的源碼就會知道,其實,android只是調用了這個Runnable對象的run方法而已,并沒有啟動新的線程,而且我們不應該在run方法中進行耗時操作,因為這個run方法最終是在UI線程里面執行的。也就是說,run方法里面只應該放更新UI的代碼,handleMessage方法也一樣。
?
如果你要看這部分源代碼的話,相信這個圖對你會有幫助:
?
?
?
HandlerActivity03主要代碼:
Java代碼???
?
?這個方法確實挺好,因為它為你封裝了許多操作,你只需要記住在doInBackground方法中寫耗時操作的代碼,在onPostExecute方法中寫更新UI的方法就行了。
總結
以上是生活随笔為你收集整理的andorid程序UI线程下开启子线程闪退错误解决的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解读设计模式----简单工厂模式(Sim
- 下一篇: PartitionMotionSearc