相信大家對線程應該不會太陌生了,線程是進程中的實體,它的生命周期:1.新建 2.就緒 3.運行 4.阻塞 5.死亡。
當我們編寫的Android的UI程序運行後,系統創建了一個叫做“main”的線程,我們可以通過Debug模式進行觀看:
這個Main線程也就是主線程,它在Android系統中也叫UI線程。
它負責分發事件給構件,包括繪制事件。例如,當你觸摸屏幕上的一個按鈕時,UI線程會分發一個觸摸事件給構件,
然後,構件會設定自己為被按下的狀態,並拋出一個請求給事件隊列,UI線程隊列接收請求並通知構件繪制自己。
它是非UI安全的,也就是說,不接受非UI線程的修改請求。當我們通過別的線程(非主線程或者說是非原始線程)來修改它的時候,
會拋出這個異常:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
CalledFromWrongThreadException 這個字面上都理解過來了,是說這個請求來自於錯誤的線程。
Only the original thread that created a view hierarchy can touch its views 只有最初創建視圖層次結構的線程才可以接觸到這些視圖。
也就是說android中相關的view和控件不是線程安全的,我們可以采用以下幾種方式:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
AsyncTask
其中我認為最簡單的而且最沒用的就是runOnUiThread了,只要給它一個Runnable,它輕輕松松就運行在UIThread了。但就是因為這個輕輕松松,我們的問題也來了。
因為它是運行在UI線程,也就是給用戶展示和操作的線程,我們用它去執行一些操作的話,這個線程就會進入一個阻塞的狀態,如果阻塞狀態超過5秒的話,系統就
會過來提示你了,這樣給用戶的體驗很不好,如下圖:
這時我們就需要用到上面介紹的另外幾種方式來處理,這裡介紹下一最常用的Handler。
Handler的使用場合:
1 安排messages和runnables在將來的某個時間點執行。
2 將action入隊以備在一個不同的線程中執行。即可以實現線程間通信。
比如當你創建子線程時,你可以在你的子線程中拿到父線程中創建的Handler對象,就可以通過該對象向父線程的消息隊列發送消息了。
由於Android要求在UI線程中更新界面,因此,可以通過該方法在其它線程中更新界面。
下面是完整代碼,你可以直接跳過看我後面的斷點調試。
這時這個線程的狀態變化是:1.新建 2.就緒 3.運行。
然後我們在子線程中找到父線程中創建的Handler對象myHandler,然後向它發送一個Message,在這個Message中,可以傳遞任意我們想傳遞的數據,
這裡我沒有什麼好傳的,所以直接new了一個過去。然後myHandler接到這個Message,進入handleMessage方法,在方法裡我對ProgressBar的進度每次加10,
並把它顯示在TextView上,我們可以很明顯地看到TextView的變化,說明UI線程並沒有處於阻塞狀態,界面也沒有假死。最後ProgressBar的進度到了100%,
也就到了這條語句System.out.println("used for breakPoint");當該語句沒有執行時,剛才新建的線程是還存在的,當該語句結束後,也就是該線程的run方法結束後,
這個線程的任務也就完成了,這時它即將進行第5個狀態-死亡。但它不是立即死亡,它將作為一個小垃圾被系統回收。當系統執行完執行相關的內存釋放操作後,
這個線程就自動結束了,我們可以在Debug中看到虛擬機已經找不到這個進程了
,至此該線程死亡。
我通過線程的生命周期來講解了一下Handle的用法,如果你認為我表達的意思中有錯誤的觀點或者有任何疑問,都歡迎給我留言,謝謝指點。