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()循环便可。

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息