Handler

一個Handler能夠發送、處理和線程的消息隊列關聯的Message和Runnable對象。每個Handler實例與一個線程以及這個線程的消息隊列相關。當建立一個新的Handler對象,它就會綁定到建立它的線程/消息隊列。它能夠分發Message對象和Runnable對象到主線程中。
java

Handler包含了兩個隊列,一個是線程隊列,一個是消息隊列。使用post方法會將線程對象放到該handler的線程隊列中,使用sendMessage(Message message)將消息放到消息隊列中。handler.post(r)並無單獨開啓一個新的線程,而是仍然在當前Activity線程中執行,handler只是調用了Runnable對象的run方法。android

它有兩個做用:canvas

  1. 安排Message對象和Runnable對象在線程的指定位置執行安全

  2. 使一個action在其餘線程中執行併發

當應用程序啓動時,Android首先會開啓一個主線程(UI線程),主線程管理界面中的UI控件。如界面上有一個Button, 點擊button時,android會分發事件來響應操做,這個過程都是在主線程中進行。這時若是須要一個耗時的操做,那麼界面會出現假死現象,若是5s沒完成,android系統會給一個錯誤提示"強制關閉"。因此應該把這些耗時的操做放在一個子線程中,由於子線程的操做涉及到UI更新,而主線程是線程不安全的,能夠用Handler解決。由於Handler運行在主線程中,它和子線程能夠經過Message對象來傳遞數據。Handler負責接收子線程傳過來的Message對象(子線程中經過sendMessage()傳遞),而後把消息放入主線程隊列中,配合主線程更新UI.ide


例一:oop

public class ProgressBarActivity extends Activity {
    ProgressBar pb;
    Button begin;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        pb = (ProgressBar) findViewById(R.id.pb);
        pb.setMax(100);
        begin = (Button)findViewById(R.id.begin);
        begin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                pb.setVisibility(View.VISIBLE);
                //⑴點擊begin按鈕,將要執行的線程對象myThread放到線程隊列中
                handler.post(myThread); 
            }
        });
    }

    Handler handler = new Handler(){
        
        //⑷執行handleMessage
        public void handleMessage(Message msg) {
            pb.setProgress(msg.arg1);
            
            //當進度條已滿,將線程對象從隊列中移除
            if(msg.arg1==pb.getMax()){
                handler.removeCallbacks(myThread);
            }else{
                handler.post(myThread);
            }
        }
    };

    
    //⑵線程開始執行
    Runnable myThread = new Runnable() {
        int i = 0;
        public void run() {
            System.out.println("begin thread");
            i+=10;
            Message msg = handler.obtainMessage();
            msg.arg1 = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //⑶將Message對象加入到消息隊列中,handler接收消息一定要執行handleMessage(Message msg)
            handler.sendMessage(msg);
            
            if(i==100){
                //當i==100,將線程對象從隊列中移除,因爲handler接收消息會執行handleMessage,因此此處的代碼無心義
                handler.removeCallbacks(myThread);
            }
        }
    };
}

若是上面的代碼中,handleMessage(Message msg)修改成:post

public void handleMessage(Message msg) {
    pb.setProgress(msg.arg1);
    handler.post(myThread);
}

那麼在i=100時,雖然線程中執行了handler.removeCallbacks(myThread),當時仍然會繼續run方法,繼續打印begin thread。由於在線程的run方法執行後在handleMessage裏,handler.post(myThread)又把線程加入線程隊列,因此仍然會繼續執行線程。this


以上代碼的執行過程:點擊begin按鈕後,將myThread線程對象加入到線程隊列中,線程執行,併發出Handler消息通知UI更新,Handler接收消息執行handleMessage,更新UI。spa

注意:若是handler要接收消息,那麼就得執行handleMessage方法。


例二:

public class AHandler extends Activity {
    Handler handler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handler.post(r);
        Log.d("M====>", "main");
        setContentView(R.layout.main);
    }

    Runnable r = new Runnable() {
        @Override
        public void run() {
            Log.d("T====>","tread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
}
執行結果:
M====> main
T====> tread
Handler在主線程,因此不管在onCreate()方法裏handler.post(r)不管出於那個位置,在執行時,是在主線程中添加r消息隊列,而不是另外開啓一條新線程,主線程代碼執行完畢,就執行線程r。
因此先打印M====> main,而後再打印線程r裏的T====> tread


例三:忽略BoundView class( onDraw(Canvas canvas) )

public class BounceActivity extends Activity {
    protected static final int GUIUPDATEIDENTIFIER = 0x101;
    BounceView bounceView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.bounceView = new BounceView(this);
        this.setContentView(this.bounceView);
        new Thread(new MyThread()).start();
    }

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case BounceActivity.GUIUPDATEIDENTIFIER:
                    bounceView.invalidate();
                    break;
            }
            super.handleMessage(msg);
        }
    };

    class MyThread implements Runnable{
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                Message msg = new Message();
                msg.what = BounceActivity.GUIUPDATEIDENTIFIER;
                BounceActivity.this.handler.sendMessage(msg);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}
運行正常. 在主線程中new Thread(new MyThread()).start()開啓了一條新的線程。
雖然在run()方法中循環執行handler.sendMessage(),由於這個操做處於子線程中,因此主線程的handler的Looper監聽到有消息,就會執行handleMessage()


例四: 將例三的代碼作了修改。

onCreate()方法裏將new Thread(new MyThread()).start()修改成handler.post(r). 

public class BounceActivity extends Activity {
    protected static final int GUIUPDATEIDENTIFIER = 0x101;
    BounceView bounceView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.bounceView = new BounceView(this);
        this.setContentView(this.bounceView);
        handler.post(r);
    }

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case BounceActivity.GUIUPDATEIDENTIFIER:
                    bounceView.invalidate();
                    break;
            }
            super.handleMessage(msg);
        }
    };

    Runnable r = new Runnable() {
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                Message msg = handler.obtainMessage();
                msg.what = BounceActivity.GUIUPDATEIDENTIFIER;
                handler.sendMessage(msg);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    };
}
主線程代碼執行完畢後,執行r,可是卻不執行handleMessage()。

例4,由於handler屬於主線程,handler.post(r)並非單獨開啓一條新線程,它只是執行r 線程的run()方法,在run()方法裏有個while()致使循環執行,因爲handler和這個run()方法的操做同屬一條線程,因此只有run()執行完畢,纔會執行handleMessage()。例4想要執行handleMessage()方法,去掉run()方法的while()循環便可。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息