线程对象Android 开发之多线程处理、Handler 详解
發一下牢騷和主題無關:
????
每日一道理毅力,是千里大堤一沙一石的凝聚,一點點地累積,才有前不見頭后不見尾的壯麗;毅力,是春蠶吐絲一縷一縷的環繞,一絲絲地堅持,才有破繭而出重見光明的輝煌; 毅力,是遠航的船的帆,有了帆,船才可以到達成功的彼岸。
????
Android開發過程當中為什么要多線程
我們創立的Service、Activity以及Broadcast均是一個主線程處置,這里我們可以懂得為UI線程。但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數據庫操作以及網絡下載須要很長時間,為了不阻塞用戶界面,出現ANR的響應提示窗口,這個時候我們可以斟酌使用Thread線程來解決。
? Android中使用Thread線程會遇到哪些問題
對于從事過J2ME開發的程序員來講Thread比較簡單,直接匿名創立重寫run方法,調用start方法執行即可。或者從Runnable接口繼承,但對于Android平臺來講UI控件都沒有設計成為線程安全類型,所以須要引入一些同步的機制來使其刷新,這點Google在設計Android時倒是參考了下Win32的消息處置機制。
postInvalidate()方法
對于線程中的刷新一個View為基類的界面,可以使用postInvalidate()方法在線程中來處置,其中還供給了一些重寫方法比如postInvalidate(int left,int top,int right,int bottom)?來刷新一個矩形區域,以及延時執行,比如postInvalidateDelayed(long delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int left,int top,int right,int bottom)?方法,其中第一個參數為毫秒,如下:
| void | postInvalidate() |
| void | postInvalidate(int left, int top, int right, int bottom) |
| void | postInvalidateDelayed(long delayMilliseconds) |
| void | postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom) |
Handler
當然推薦的方法是通過一個Handler來處置這些,可以在一個線程的run方法中調用handler對象的postMessage或sendMessage方法來實現,Android程序外部維護著一個消息隊列,會輪訓處置這些,如果你是Win32程序員可以很好懂得這些消息處置,不過相對于Android來講沒有供給PreTranslateMessage這些干預外部的方法。
消息的處置者,handler負責將須要傳遞的信息封裝成Message,通過調用handler對象的obtainMessage()來實現。將消息傳遞給Looper,這是通過handler對象的sendMessage()來實現的。繼而由Looper將Message放入MessageQueue中。當Looper對象看到MessageQueue中含有Message,就將其廣播出去。該handler對象收到該消息后,調用相應的handler對象的handleMessage()方法對其停止處置。
?
Handler主要接受子線程發送的數據,并用此數據配合主線程更新UI.
??????當應用程序啟動時,Android首先會開啟一個主線程?(也就是UI線程) ,?主線程為管理界面中的UI控件,停止事件分發,比如說,你要是點擊一個?Button ,Android會分發事件到Button上,來響應你的操作。??如果此時須要一個耗時的操作,例如:聯網讀取數據,?或者讀取當地較大的一個文件的時候,你不能把這些操作放在主線程中,,如果你放在主線程中的話,界面會出現假死景象,如果5秒鐘還沒有實現的話,,會收到Android系統的一個錯誤提示? "強制關閉".??這個時候我們須要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的.這個時候,Handler就出現了,來解決這個復雜的問題,?由于Handler運行在主線程中(UI線程中),??它與子線程可以通過Message對象來傳遞數據,這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳弟)Message對象,(里面包括數據)? ,把這些消息放入主線程隊列中,配合主線程停止更新UI。
Handler一些特點:handler可以分發Message對象和Runnable對象到主線程中,每一個Handler實例,都會綁定到創立他的線程中(一般是位于主線程),
??????它有兩個作用: (1)安排消息或Runnable在某個主線程中某個地方執行
?????????????????????????? (2)安排一個動作在不同的線程中執行
??????? Handler平分發消息的一些方法
??????? post(Runnable)
??????? postAtTime(Runnable,long)
??????? postDelayed(Runnable long)
??????? sendEmptyMessage(int)
??????? sendMessage(Message)
??????? sendMessageAtTime(Message,long)
??????? sendMessageDelayed(Message,long)
??????以上post類方法答應你排列一個Runnable對象到主線程隊列中,sendMessage類方法,答應你安排一個帶數據的Message對象到隊列中,等待更新.
Handler實例
????//?子類須要繼承Hendler類,并重寫handleMessage(Message msg)?方法,用于接受線程數據
???? //?以下為一個實例,它實現的功能為?:通過線程修改界面Button的內容
public class MyHandlerActivity extends Activity {
??? Button button;
??? MyHandler myHandler;
??? protected void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? setContentview(R.layout.handlertest);
??????? button = (Button) findViewById(R.id.button);
??????? myHandler = new MyHandler();
??????? //當創立一個新的Handler實例時,它會綁定到當前線程和消息的隊列中,開始分發數據
??????? // Handler有兩個作用, (1) :定時執行Message和Runnalbe對象
??????? // (2):讓一個動作,在不同的線程中執行.
??????? //它安排消息,用以下方法
??????? // post(Runnable)
??????? // postAtTime(Runnable,long)
??????? // postDelayed(Runnable,long)
??????? // sendEmptyMessage(int)
??????? // sendMessage(Message);
??????? // sendMessageAtTime(Message,long)
??????? // sendMessageDelayed(Message,long)
??????? //以上方法以?post掃尾的答應你處置Runnable對象
??????? //sendMessage()答應你處置Message對象(Message里可以包括數據,)
??????? MyThread m = new MyThread();
??????? new Thread(m).start();
??? }
??? /**
???? *接受消息,處置消息?,此Handler會與當前主線程一塊運行
???? * */
??? class MyHandler extends Handler {
??????? public MyHandler() {
??????? }
??????? public MyHandler(Looper L) {
??????????? super(L);
??????? }
??????? //子類必須重寫此方法,接受數據
??????? @Override
??????? public void handleMessage(Message msg) {
??????????? // TODO Auto-generated method stub
??????????? Log.d("MyHandler", "handleMessage......");
??????????? super.handleMessage(msg);
??????????? //此處可以更新UI
??????????? Bundle b = msg.getData();
??????????? String color = b.getString("color");
??????????? MyHandlerActivity.this.button.append(color);
??????? }
??? }
??? class MyThread implements Runnable {
??????? public void run() {
??????????? try {
??????????????? Thread.sleep(10000);
??????????? } catch (InterruptedException e) {
??????????????? // TODO Auto-generated catch block
??????????????? e.printStackTrace();
??????????? }
??????????? Log.d("thread.......", "mThread........");
??????????? Message msg = new Message();
??????????? Bundle b = new Bundle();//存放數據
??????????? b.putString("color", "我的");
??????????? msg.setData(b);
??????????? MyHandlerActivity.this.myHandler.sendMessage(msg); //向Handler發送消息,更新UI
??????? }
??? }
}
? Looper
其實Android中每一個Thread都隨著一個Looper,Looper可以幫助Thread維護一個消息隊列,昨天的問題?Can't create handler inside thread?錯誤?一文中提到這一觀點,但是Looper和Handler沒有什么關系,我們從開源的代碼可以看到Android還供給了一個Thread繼承類HanderThread可以幫助我們處置,在HandlerThread對象中可以通過getLooper方法獲得一個Looper對象控制句柄,我們可以將其這個Looper對象映射到一個Handler中去來實現一個線程同步機制,Looper對象的執行須要初始化Looper.prepare方法就是昨天我們看到的問題,同時推出時還要釋放資源,使用Looper.release方法。
Looper是MessageQueue的管理者。每一個MessageQueue都不能脫離Looper而存在,Looper對象的創立是通過prepare函數來實現的。同時每一個Looper對象和一個線程關聯。通過調用Looper.myLooper()可以獲得當前線程的Looper對象?
創立一個Looper對象時,會同時創立一個MessageQueue對象。除了主線程有默許的Looper,其他線程默許是沒有MessageQueue對象的,所以,不能接受Message。如須要接受,自己定義一個Looper對象(通過prepare函數),這樣該線程就有了自己的Looper對象和MessageQueue數據結構了。?
Looper從MessageQueue中取出Message然后,交由Handler的handleMessage停止處置。處置實現后,調用Message.recycle()將其放入Message Pool中。
Message
對于Android中Handler可以傳遞一些內容,通過Bundle對象可以封裝String、Integer以及Blob二進制對象,我們通過在線程中使用Handler對象的??? sendEmptyMessage或sendMessage方法來傳遞一個Bundle對象到Handler處置器。對于Handler類供給了重寫方法handleMessage(Message msg)?來判斷,通過msg.what來區分每條信息。將Bundle解包來實現Handler類更新UI線程中的內容實現控件的刷新操作。相關的Handler對象有關消息發送sendXXXX相關方法如下,同時還有postXXXX相關方法,這些和Win32中的道理基本一致,一個為發送后直接返回,一個為處置后才返回。
Message:消息對象,Message Queue中的存放的對象。一個Message Queue中包括多個Message。?Message實例對象的取得,通常使用Message類里的靜態方法obtain(),該方法有多個重載版本可供選擇;它的創立并不一定是直接創立一個新的實例,而是先從Message Pool(消息池)中看有沒有可用的Message實例,存在則直接取出返回這個實例。如果Message Pool中沒有可用的Message實例,則才用給定的參數創立一個Message對象。調用removeMessages()時,將Message從Message Queue中刪除,同時放入到Message Pool中。除了上面這種方式,也可以通過Handler對象的obtainMessage()獲得一個Message實例。
| final boolean | sendEmptyMessage(int what) |
| final boolean | sendEmptyMessageAtTime(int what, long uptimeMillis) |
| final boolean | sendEmptyMessageDelayed(int what, long delayMillis) |
| final boolean | sendMessage(Message?msg) |
| final boolean | sendMessageAtFrontOfQueue(Message?msg) |
| boolean | sendMessageAtTime(Message?msg, long uptimeMillis) |
| final boolean | sendMessageDelayed(Message?msg, long delayMillis) |
MessageQueue
是一種數據結構,見名知義,就是一個消息隊列,存放消息的地方。每一個線程最多只可以擁有一個MessageQueue數據結構。?
創立一個線程的時候,并不會自動創立其MessageQueue。通常使用一個Looper對象對該線程的MessageQueue停止管理。主線程創立時,會創立一個默許的Looper對象,而Looper對象的創立,將自動創立一個Message Queue。其他非主線程,不會自動創立Looper,要須要的時候,通過調用prepare函數來實現。?
java.util.concurrent對象分析
對于過去從事Java開發的程序員不會對Concurrent對象感到陌生吧,他是JDK 1.5以后新增的重要特性作為掌上設備,我們不提倡使用該類,斟酌到Android為我們已經設計好的Task機制,我們這里Android開發網對其不做過多的贅述。
Task以及AsyncTask
在Android中還供給了一種有別于線程的處置方式,就是Task以及AsyncTask,從開源代碼中可以看到是針對Concurrent的封裝,開發人員可以方便的處置這些異步任務。?當然涉及到同步機制的方法和技巧還有很多,斟酌時間和篇幅問題不再做過多的描述。
文章結束給大家分享下程序員的一些笑話語錄: 一個合格的程序員是不會寫出 諸如 “摧毀地球” 這樣的程序的,他們會寫一個函數叫 “摧毀行星”而把地球當一個參數傳進去。
--------------------------------- 原創文章 By
線程和對象
---------------------------------
轉載于:https://www.cnblogs.com/jiangu66/archive/2013/05/28/3104983.html
總結
以上是生活随笔為你收集整理的线程对象Android 开发之多线程处理、Handler 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nullnullGet previo
- 下一篇: 头一回看到反馈