標籤:
我學習Handler是按照這樣的思路,所以我也按照這個的思路來寫:1.Handler是什嗎?2. Handler幹了些什嗎?3.我們應該怎樣利用Handler針對不同的情境來實現不同的功能 (一) Handler是什嗎? Handler,顧名思義就是“處理者”,用來發送和接受資訊並且按照資訊的匹配來實現執行功能代碼。它包含線程隊列和訊息佇列,實現非同步訊息處理機制在android裡面被運用很巧妙。 Androud啟動時,首先會開啟一個主線程 (也就是UI線程) , 主線程為管理介面中的UI控制項,進行事件分發,來響應客戶的操作。 如果此時需要一個耗時的操作,例如: 要連網去下載一個東西,我們是不能把這些操作放在主線程中,會很容易導致“ARN”異常。如果你放在主線程中的話,介面會出現假死現象, 如果5秒鐘還沒有完成的話,,會收到Android系統的一個錯誤提示 "強制關閉". 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的. 這個時候,Handler就出現了.,來解決這個複雜的問題 , 由於Handler運行在主線程中(UI線程中), 它與子線程可以通過Message對象來傳遞資料, 這個時候,Handler就承擔著接受子線程傳過來的(子線程用sendMessage()方法傳弟)Message對象,(裡麵包含資料) , 把這些訊息放入主線程隊列中,配合主線程進行更新UI。 (二) Handler幹了些什嗎? handler可以分發Message對象和Runnable對象到主線程中, 每個Handler執行個體,都會綁定到建立它的線程中(一般是位於主線程), 它有兩個作用: (1)安排訊息或Runnable 在某個主線程中某個地方執行; (2)安排一個動作在不同的線程中執行 那麼,要實現上述的兩個功能,我們得基於發送和接受資訊的基礎,先瞭解下怎麼發送和處理。 它分發訊息的一些方法 post(Runnable) postAtTime(Runnable,long) postDelayed(Runnable long) sendEmptyMessage(int) sendMessage(Message) 將訊息發送到訊息佇列 msg.sendToTarget() 將訊息發送到訊息佇列 sendMessageAtTime(Message,long) 定時將訊息發送到訊息佇列 sendMessageDelayed(Message,long) 延遲一定時間後,將訊息發送到訊息佇列 以上post類方法允許你排列一個Runnable對象到主線程隊列中, sendMessage類方法, 允許你安排一個帶資料的Message對象到隊列中,等待更新.(Message裡可以包含資料) 知識補充之Message怎麼包含資料:(1)Message對象 Message對象攜帶資料,通常它用arg1,arg2來傳遞訊息,當然它還可以有obj參數,可以攜帶Bundle資料。它的特點是系統效能消耗非常少。 初始化: Message msg=handler.obtainMessage();(2)Bundle對象 Bundle是Android提供的類,可以把它看做是特殊的Map,即索引值對的包。而它特殊在鍵和值都必須要是基礎資料型別 (Elementary Data Type)或是基礎資料型別 (Elementary Data Type)的數組(Map的索引值要求都是對象),特別的,鍵要求都是String類型。用Message來攜帶Bundle資料: 放入:msg.setData(Bundle bundle); 取出:msg.getData(); 一般我都是藉助Bundle類。代碼 Bundle bundle = new Bundle(); bundle.putInt("myage", 21); bundle.putString("myname", "yummylau"); msg.setData(bundler); msg.sendToTarget(); 代碼 Bundle myData = msg.getData(); int myage = myData.getInt("myage"); String myname = myData.getString("myname"); 希望對大家有協助。 它處理訊息的一般做法 訊息的具體處理過程,需要在new Handler對象時使用匿名內部類重寫Handler的handleMessage(Message msg)方法,如下: Handler handler=new Handler(){ @Override public void handleMessage(Message msg) //寫上自己想要執行的功能代碼 } }; (三)我們應該怎樣利用Handler針對不同的情境來實現不同的功能 一般我們建立一個Handler對象,主要是想利用Handler來和UI線程互動,Handlre可以是UI線程的,也可以是新線程裡面的。 (1)通過handler的延時發送message,可以延時處理一些事務的處理 比如我想設計某一個應用的啟動時有一個歡迎介面,讓這個介面停留幾秒後再跳轉到裡一個Activity首頁 public class SplashActivity extends Activity{ private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.splash); startMainAvtivity(); } private void startMainAvtivity(){ new Handler().postDelayed(new Runnable(){ @Override public void run() { intent = new Intent(SplashActivity.this,MainActivity.class); startActivity(intent); SplashActivity.this.finish(); } }, 3000); } } } 上述紅色代碼的利用Handler來延遲啟動另一個Activity。 值得注意的是:有一些小夥伴會認為,我們在主線程裡面啟動了新線程,然後在新線程裡面跳轉了Activity。其實一開始我也是這樣認為的,在學習的過程中看到了一位網上的朋友寫的博文和測試,也反思了一下,請教了一些師兄。只要記住:java裡面啟動新線程有兩種方法(個人知識所限),一種是利用一個類去繼承Thread,然後執行個體化後執行start()方法;另一種是實現Runable介面,把Runnable對象作為參數去執行個體化一個Thread對象再執行start()方法。 下面例子是參考網上朋友的:Java代碼 package org.hualang.handlertest3; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; public class HandlerTest3 extends Activity { private Handler handler = new Handler(); private String TAG = "System.out"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler.post(r); setContentView(R.layout.main); //Thread t = new Thread(r); //t.start(); Log.d(TAG,"Activity id:"+Thread.currentThread().getId()); Log.d(TAG,"Activity name:"+Thread.currentThread().getName()); } Runnable r = new Runnable() { public void run() { Log.d(TAG,"Handler id:"+Thread.currentThread().getId()); Log.d(TAG,"Handler name:"+Thread.currentThread().getName()); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; } 運行結果證明是同一個線程的兩個依據:①Activity的id或name和Handler的id或name是同樣的②設定了 handler.post(r); setContentView(R.layout.main);也就是,如果執行後馬上顯示文本資訊,那麼可以證明它們不在同一個線程,但是實際情況是要先執行了handler後5秒,才顯示文本資訊,說明它們在同一線程如果將代碼改為 handler.post(r); setContentView(R.layout.main); Thread t = new Thread(r); t.start(); 再次執行,運行結果如下,通過start啟動線程,它們不在同一個線程中(2)利用handler發送message,然後不同線程接受和處理該訊息。顯然,我們在Android裡面利用Handler更多的是想在非同步線程裡面實現我們想要的東西 我把Handler處理非同步分解成兩個方面: △1在UI線程建立Handler,由非UI線程發送資訊UI線程接受資訊;(用於更新UI)代碼:運行結果:這個例子和上述的例子相似,不過在與Handler建立的線程不一樣。上述例子比較局限,因為我們在做項目的時候不可能都寫在同一檔案裡面,如果我們在不同檔案而要拿到同一個Handler對象,我們可以考慮利用“構造器”的方法,把Handler對象作為參數進行傳遞,就可以實現不同檔案的公用;或者我們可以定義成static。 android中其實還給了我們一個類HandlerThread,該類封裝好了Looper和MessageQueue(個人測試之後認為,如果不對請指出哦)。例子是按照上面的例子改寫的,非UI線程處理UI線程發送的訊息。直接上代碼:運行結果:從例子上看 ,效果是和上一個例子基本是一樣的,少了Looper.prepare()和Looper.loop();本人對這個類不太熟悉,請大神指點一二。 在使用Handler的時候只要時刻謹記Handler在哪一個線程建立post執行所在的線程;HandlerUI線程操作和非UI線程操作的區別和定時執行某些動作。就能基本掌握了。android非同步線程還可以使用AsyncTask執行非同步任務。其底層實現還是基於Handler。 原文地址:http://www.360doc.com/content/14/0108/13/7673502_343568991.shtml
android企業開發學習——handler