Handler機制的簡單原理

Handler機制的簡單原理



因爲android UI界面不是線程安全的,不允許子線程更新主UI線程,爲了達到主界面的更新操作,此時便有了Handler對象.

Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。Android利用Handler來實現UI線程的更新的。

HandlerAndroid中的消息發送器,其在哪個Activity中創建就屬於且緊緊屬於該Activity。還可以說其在哪個線程中new的,就是那個線程的Handler

 

Handler的定義主要接受子線程發送的數據並用此數據配合主線程更新UI. 



在UI線程

handler對象首先在主界面中進行聲明,並覆蓋其中的handleMessage(msg)方法。該方法用來接收子線程傳遞來的Message對象。




在子線程:

子線程啓動後,首先創建Message對象。然後將待發送的數據放入Message對象中,並使用handler的sendMessage(msg)來發送msg對象,發送成功夠,handleMessage(msg)拿到msg對象,並用這個msg對象裏面的數據 來在主線程中更新手機界面。


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) 

sendMessage類方法,允許你安排一個帶數據的Message對象到隊列中,等待更新.

比如看看一般歡迎界面的實現方法:


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;

public class WelcomeScreen extends Activity{
	@Override
	protected void onCreate(Bundle savedInstanceState) {		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.welcome_screen);

		Handler handler = new Handler();
		handler.postDelayed(new Loading(), 2000);//2s後執行Loading線程,  跳轉到MainActivity
	}

	class Loading implements Runnable{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			
			startActivity(new Intent(WelcomeScreen.this,MainActivity.class));
			WelcomeScreen.this.finish();
		}
	}
	
}


補充別人總結的:

1、向哪個Handler發送消息,就必須在哪個handler裏面接收;

2、直接使用JAVA Thread是無法更新Android UI的,因爲Android View在設計的時線程是不完全的,不過Android提供了幾種供開發者在線程中更新UI的方法,如下:

runOnUiThread( Runnable )

post( Runnable )

postDelayed( Runnable, long )

3、直接使用hanlder.post等方法是在當前主線程裏面做操作,而不是另外新建線程,建議使用Thread線程直接新建另外一個線程或者使用HandlerThread類也可以。(這句話的意思是ui線程是主線程,把一些耗時的操作放入其他線程做,主線程僅僅更新視圖)

4、記住消息隊列的先進先出原則。 






需要注意的:

 

. HandlerThread的區別。

 

Handler與調用者處於同一線程,如果Handler裏面做耗時的動作,調用者線程會阻塞。Android UI操作不是線程安全的,並且這些操作必須在UI線程中執行。Android提供了幾種基本的可以在其他線程中處理UI操作的方案,包括ActivityrunOnUiThread(Runnable),Viewpost以及1.5版本的工具類AsyncTask等方案都採用了HandlerHandlerpost對線程的處理也不是真正start一個新的線程,而是直接調用了線程的run方法,這正是google煞費苦心搞一套Handler的用意。

 

.Handler對於Message的處理不是併發的

 

一個Looper只有處理完一條Message纔會讀取下一條,所以消息的處理是阻塞形式的。但是如果用不同的Looper則能達到併發的目的。Service中,onStart的執行也是阻塞的。如果一個startServiceonStart執行完成之前,再次條用startService也會阻塞。如果希望能儘快的執行onStart則可以在onStart中使用handler,因爲Messagesend是非阻塞的。如果要是不同消息的處理也是併發的,則可以用不同的Looper實例化Handler

 

資源回收

Handler對象發送類似new Message ()形式的空Message可以達到清空Message的目的,這種做法與getLooper().quit()的做法是一樣的。如果利用的資源較多,應及時清理。


 

Android中實現view的更新有第二種方法:


Android中實現view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而後者在非UI線程中使用。
Android提供了Invalidate方法實現界面刷新,但是Invalidate不能直接在線程中調用,因爲他是違背了單線程模型:Android UI操作並不是線程安全的,並且這些操作必須在UI線程中調用。

 Android程序中可以使用的界面刷新方法有兩種,分別是利用Handler和利用postInvalidate()來實現在線程中刷新界面。
1,利用invalidate()刷新界面
  實例化一個Handler對象,並重寫handleMessage方法調用invalidate()實現界面刷新;而在線程中通過sendMessage發送界面更新消息。

2,使用postInvalidate()刷新界面

使用postInvalidate則比較簡單,不需要handler,直接在線程中調用postInvalidate即可。

程序如下:

   /**
       *    1 利用invalidate()刷新界面  
       *    實例化一個Handler對象,並重寫handleMessage方法.
       *    調用invalidate()實現界面刷新;
       *    而在線程中通過sendMessage發送界面更新消息。 
       *    
       */

      // 在onCreate()中開啓線程
        new Thread(new GameThread()).start();
        
     // 實例化一個handler

        Handler myHandler = new Handler() {
	        // 接收到消息後處理
	        public void handleMessage(Message msg) {
		        switch (msg.what) {
			        case Activity01.REFRESH: mGameView.invalidate(); // 刷新界面
			        break;
		        }
		        super.handleMessage(msg);
	        }
        }; 
        
    }
    
    class GameThread implements Runnable {
        public void run() {
	        while (!Thread.currentThread().isInterrupted()) {
		        Message message = new Message();
		        message.what = Activity01.REFRESH;
		        // 發送消息
		        Activity01.this.myHandler.sendMessage(message);
		        try {
		        	Thread.sleep(100);
		        } catch (InterruptedException e) {
		        	Thread.currentThread().interrupt();
		        }
	        }
        }
    }
    
    
    //2,使用postInvalidate()刷新界面 
   // 使用postInvalidate則比較簡單,不需要handler,直接在線程中調用postInvalidate即可。 

    class GameThread2 implements Runnable { 
	    public void run() { 
		    while (!Thread.currentThread().isInterrupted()) { 
			    try { 
			    	Thread.sleep(100); 
			    } catch (InterruptedException e) { 
			    	Thread.currentThread().interrupt(); 
			    } 
			    // 使用postInvalidate可以直接在線程中更新界面 
			    mGameView.postInvalidate(); 
		    } 
	    } 
    }
 







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章