Handler消息传递机制学习

一:为什么要使用Handler ?

当在Android应用中执行耗时操作时,为了避免主线程(UI线程)拥塞,通常会新开一个非主线程去执行耗时任务,当耗时任务执行完并需要根据执行的结果去更新主线程中的UI组件时,如果在非主线程中直接更新UI很可能会导致线程安全问题,所以Android规定必须在UI线程中去更新组件,那么就要将非主线程中的结果发送到UI线程,而Handler就是起到将非UI线程中的数据发送到UI线程中去的作用,UI线程通过Handler的handleMessage()方法获取Handler发送过来的数据,并根据这些数据在UI线程中更新UI。


从上面可以看到Handler的作用为:

1.  在非UI线程中发送消息(消息中可以包含数据)。

2.  在UI线程中去获取、处理消息。

Handler工作流程:Handler先将消息(Message)发送到Looper管理的消息队列(MessageQueue),然后Handler在MessageQueue获取、处理Message。 Handler消息传递是一个自己发号命令然后自己去获取并执行的机制。


在子线程使用Handler必须自己创建Looper对象(通过Looper.prepare()创建),发送消息后使用Looper.loop启动Looper,Looper是用来管理消息队列的。主线程中因为系统已经初始化了一个Looper对象,所以不需要程序员去创建了,直接使用Handler即可

下满是Handler的使用例子,加深理解:

public class MainActivity extends AppCompatActivity {
    private final String NUMSTR = "number";
    private TextView tv;
    private Handler handler = new Handler(){
        // 主线程从消息队列中获取消息并提取数据
        public void handleMessage(Message msg){
            if(msg.what == 0x123){
                int number = msg.getData().getInt(NUMSTR);
                //  更新UI
                tv.setText(number+"");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView)findViewById(R.id.tv);
        MyThread thread = new MyThread();
        //  启动线程
        thread.start();
    }
    //  耗时任务子线程中执行
    class MyThread extends Thread{
        int number = 0;
        public void run(){

            while(true){
                try {
                    //  模拟耗时任务
                    Thread.sleep(3000);
                    number++;
                    Message message = Message.obtain();
                    message.what = 0x123;
                    Bundle bundle = new Bundle();
                    bundle.putInt(NUMSTR,number);
                    message.setData(bundle);
                    //  handler发送消息到主线程
                    handler.sendMessage(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
因为是在主线程中使用Handler,所以并不需要创建和启动Looper。若在子线程中使用Handler就需要创建和启动Looper,示例代码如下:

public class MainActivity extends AppCompatActivity {
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyThread thread = new MyThread();
        //  启动线程
        thread.start();
    }
    class MyThread extends Thread{
        public void run(){
            Looper.prepare();    //  Looper.prepare()和Looper.loop()包起来的是个循环体
               handler = new Handler(){
                // 主线程从消息队列中获取消息并提取数据
                public void handleMessage(Message msg){
                    if(msg.what == 0x123){
                        Toast.makeText(MainActivity.this, "Boom", Toast.LENGTH_SHORT).show();
                    }
                }
            };
            Looper.loop();  这句代码后的代码都不会执行
        }
    }
    public void click(View v){    // 一个按钮的点击事件
        handler.sendEmptyMessage(0x123);
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值