日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

andorid程序UI线程下开启子线程闪退错误解决

發布時間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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();??
  • ????}??
  • });??
  • ?

    ?這是一種錯誤的做法,運行程序,會報錯誤:

    Java代碼???

  • android.view.ViewRootImpl$CalledFromWrongThreadException:?Only?the?original?thread?that?created?a?view?hierarchy?can?touch?its?views.???
  • ?

    ?

    ?

    ?

    ?

    ?HandlerActivity02主要代碼:

    Java代碼???

  • 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));??
  • ????????}??
  • ??????????
  • ????};??
  • }??
  • ?這里有個容易出錯的地方,在更新UI方法2和3中,我們傳入的參數是一個Runnable對象,一般認為這就會啟動一個新的線程,而且常有人在這個Runnable對象的run方法中進行耗時操作。看過這塊的源碼就會知道,其實,android只是調用了這個Runnable對象的run方法而已,并沒有啟動新的線程,而且我們不應該在run方法中進行耗時操作,因為這個run方法最終是在UI線程里面執行的。也就是說,run方法里面只應該放更新UI的代碼,handleMessage方法也一樣。

    ?

    如果你要看這部分源代碼的話,相信這個圖對你會有幫助:

    ?

    ?

    ?

    HandlerActivity03主要代碼:

    Java代碼???

  • 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);??
  • ????????}??
  • ??????????
  • ????}??
  • ??
  • }??
  • ?

    ?這個方法確實挺好,因為它為你封裝了許多操作,你只需要記住在doInBackground方法中寫耗時操作的代碼,在onPostExecute方法中寫更新UI的方法就行了。

總結

以上是生活随笔為你收集整理的andorid程序UI线程下开启子线程闪退错误解决的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。