編輯:關於Android編程
主要接受子線程發送的數據, 並用此數據配合主線程更新UI。
解釋: 當應用程序啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控件,進行事件分發,比如說,你要是點擊一個 Button ,Android會分發事件到Button上,來響應你的操作。
如果此時需要一個耗時的操作,例如:聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象,如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示 "強制關閉"。 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的。
這個時候,Handler就出現了。來解決這個復雜的問題,由於Handler運行在主線程中(UI線程中),它與子線程可以通過Message對象來傳遞數據,這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳弟)Message對象,(裡面包含數據),把這些消息放入主線程隊列中,配合主線程進行更新UI。
handler類允許你發送消息和處理線程消息隊列中的消息及runnable對象。handler實例都是與一個線程和該線程的消息隊列一起使用,一旦創建了一個新的handler實例,系統就把該實例與一個線程和該線程的消息隊列捆綁起來,這將可以發送消息和runnable對象給該消息隊列,並在消息隊列出口處處理它們。
handler類有兩種主要用途:1。按照時間計劃,在未來某時刻,對處理一個消息或執行某個runnable實例。2。把一個對另外線程對象的操作請求放入消息隊列中,從而避免線程間沖突。
時間類消息通過如下方法使用: post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long)
methods.post之類函數可以傳輸一個runnable對象給消息隊列,並在到達消息隊列後被調用。sendmessage之類函數可以傳送一個包含數據的message對象,該message對象可以被Handler類的handleMessage(Message) 方法所處理。
post之類函數和sendmessage之類的函數都可以指定消息的執行時機,是立即執行、稍後一段時間執行,還是在某個確定時刻執行。這可以用來實現超時、消息或其他時間相關的操作。
當一個進程啟動時,主線程獨立執行一個消息隊列,該隊列管理著應用頂層的對象(如:activities、broadcast receivers等等)和所有創建的窗口。你可以創建自己的一個線程,並通過handler來與主線程進行通信。這可以通過在新的線程中調用主線程的handler的post和sendmessage操作來實現。
HandlerThread/Looper & MessageQueue & Message的關系:
handler負責將需要傳遞的信息封裝成Message,通過handler對象的sendMessage()來將消息傳遞給Looper,由Looper將Message放入MessageQueue中。當Looper對象看到MessageQueue中含有Message,就將其廣播出去。該handler 對象收到該消息後,調用相應的handler對象的handleMessage()方法對其進行處理。
handler可以分發Message對象和Runnable對象到主線程中,每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程),它有兩個作用:
(1): 安排消息或Runnable 在某個主線程中某個地方執行。
(2)安排一個動作在不同的線程中執行。
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post類方法允許你排列一個Runnable對象到主線程隊列中,
sendMessage類方法, 允許你安排一個帶數據的Message對象到隊列中,等待更新.
public class HandlerTest extends Activity { /** Called when the activity is first created. */ private Button startButton; private Button endButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 根據id獲得控件對象 startButton = (Button) findViewById(R.id.startButton); endButton = (Button) findViewById(R.id.endButton); // 為控件設置監聽器 startButton.setOnClickListener(new StartButtonListener()); endButton.setOnClickListener(new EndButtonListener()); } class StartButtonListener implements OnClickListener { public void onClick(View v) { // 調用Handler的post()方法,將要執行的線程對象放到隊列當中 handler.post(updateThread); } } class EndButtonListener implements OnClickListener { public void onClick(View v) { // 調用Handler的removeCallbacks()方法,刪除隊列當中未執行的線程對象 handler.removeCallbacks(updateThread); } } // 創建Handler對象 Handler handler = new Handler(); // 新建一個線程對象 Runnable updateThread = new Runnable() { // 將要執行的操作寫在線程對象的run方法當中 public void run() { System.out.println("updateThread"); // 調用Handler的postDelayed()方法 // 這個方法的作用是:將要執行的線程對象放入到隊列當中,待時間結束後,運行制定的線程對象 // 第一個參數是Runnable類型:將要執行的線程對象 // 第二個參數是long類型:延遲的時間,以毫秒為單位 handler.postDelayed(updateThread, 3000); } }; }
一個應用程序中有一個進度條和一個按鈕,當點擊按鈕後,每隔一秒鐘進度條前進一部分。
下圖為應用程序的運行效果圖:
public class ProgressBarHandlerTest extends Activity { /** Called when the activity is first created. */ private ProgressBar progressBar; private Button startButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); progressBar = (ProgressBar) findViewById(R.id.progressbar); startButton = (Button) findViewById(R.id.startButton); startButton.setOnClickListener(new ProgressBarOnClickListener()); } class ProgressBarOnClickListener implements OnClickListener { public void onClick(View v) { // 設置進度條為可見狀態 progressBar.setVisibility(View.VISIBLE); updateBarHandler.post(updateThread); } } // 使用匿名內部類來復寫Handler當中的handlerMessage()方法 Handler updateBarHandler = new Handler() { @Override public void handleMessage(Message msg) { progressBar.setProgress(msg.arg1); updateBarHandler.post(updateThread); // 將要執行的線程放入到隊列當中 } }; // 線程類,該類使用匿名內部類的方式進行聲明 Runnable updateThread = new Runnable() { int i = 0; public void run() { // TODO Auto-generated method stub System.out.println("Begin Thread"); i += 10; // 得到一個消息對象,Message類是android系統提供的 Message msg = updateBarHandler.obtainMessage(); // 將Message對象的arg1參數的值設置為i msg.arg1 = i; // 用arg1、arg2這兩個成員變量傳遞消息,優點是系統性能消耗較少 try { Thread.sleep(1000); // 讓當前線程休眠1000毫秒 } catch (InterruptedException ex) { ex.printStackTrace(); } // 將Message對象加入到消息隊列當中 updateBarHandler.sendMessage(msg); // 如果i的值等於100 if (i == 100) { // 將線程對象從隊列中移除 updateBarHandler.removeCallbacks(updateThread); } } }; }
Handler在默認情況下,實際上它和調用它的Activity是處於同一個線程的。
例如在Handler的使用(一)的示例1中,雖然聲明了線程對象,但是在實際調用當中它並沒有調用線程的start()方法,而是直接調用當前線程的run()方法。
通過一個例子來證實一下
一個Android應用程序,在Activity中創建Handler和線程對象,並且在Activity的onCreate()方法中輸出當前線程的id和名字,然後在線程對象的run方法中也打印輸出下當前線程的id和名字。如果說,Activity輸出的結果與線程對象輸出的結果是一樣的,那麼就表示它們使用的是同一個線程。
下面是Activity代碼:
public class HandlerTwo extends Activity { /** Called when the activity is first created. */ Handler handler = new Handler(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 在設置布局文件之前先調用post方法, // 表示在執行完線程之後才會顯示布局文件中的內容,而線程中又設置了休眠10秒鐘, // 所以最終效果為,先顯示應用程序主界面,等待10秒鐘之後才顯示布局文件中的內容 handler.post(r); setContentView(R.layout.main); System.out.println("activity id--->" + Thread.currentThread().getId()); System.out.println("activity name---> + Thread.currentThread().getName()); } Runnable r = new Runnable() { public void run() { // 輸出當前線程的id和name // 如果這裡輸出的線程id、name與上面onCreate()方法中輸出的線程id、name相同的話, // 那麼則表示,他們使用的是同一個線程 System.out.println("runnable_id---> + Thread.currentThread().getId()); System.out.println("runnable_name---> + Thread.currentThread().getName()); try { Thread.sleep(10000); // 讓線程休眠10秒 } catch (InterruptedException e) { e.printStackTrace(); } } }; }
根據結果可以看出,兩個輸出的id和name都相同,它們使用的是同一個線程。
現在將Activity中的代碼修改一下,新建一個線程Thread,然後調用線程的start()方法,再觀察一下控制台的輸出結果。
這裡只要將上面的代碼稍微修改一下就可以了。
1、先將handler.post(r)注釋掉。
2、再添加下面兩句代碼就OK了。
//handler.post(r); Thread t = new Thread(r); t.start();
從這個輸出結果中可以看出,這次線程對象的id、name與activity裡的線程id、name完全不一樣了,由此可見,它們現在使用的不是同一個線程。
這個例子中還掩飾了一個效果,就是平時我們是將Handler的post()方法放在setContentView(R.layout.main)這個方法之後調用,將設置完布局之後再執行其他的操作,而在這個例子中,是將Handler的post()方法放在setContent()方法之前調用,而post裡傳遞的線程對象的run()方法呢,又執行了休眠線程10秒鐘,所以運行實現的效果會是,當程序運行後,首先Activity上沒有任何內容,過來10秒之後,才會顯示Activity裡的內容。
這是英文文檔的第三部分:IMAGE PIPELINE GUIDE Introduction to the Image Pipeline T
Android 百分比布局1.引入:compile com.android.support:percent:24.0.02.點開源碼可以看到,主要有兩個布局類Percen
本文實例講述了Android編程之ListPreference用法。分享給大家供大家參考,具體如下:先展示一下效果圖,如下所示:項目代碼如下:package com.my
zxing是一個開放源碼的,用java實現的多種格式的1D/2D條碼圖像處理庫,它包含了聯系到其他語言的接口。可以實現使用手機的內置的攝像頭完成條形碼和二維碼的掃描與解碼