Android知识巩固—Handler

什么是Handlder?

源码对Handler的注释为—Handler是用来结合线程的消息队列来发送、处理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会关联一个线程和该线程的消息队列。当你创建一个Handler的时候,从这时开始,它就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnalbe分发到消息队列,并在它们出队的时候处理掉。
在了解Handler之前,先来了解几个基础概念。

  • UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue
  • Message:Handler接收与处理的消息对象
  • MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue
  • Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理
  • Handler:作用就是发送与处理信息

简单的来说,当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理。由于 Handler 创建在主线程,处理消息的方法也运行在主线程,因此上述中消息被 Looper 交回给 Handler 的时候就实现了“线程切换”。

Handlder作用

  • 执行定时任务:指定任务时间,在某个具体时间或某个时间段后执行特定的任务操作,例如使用Handler提供的postDelayed(Runnable r,long delayMillis)方法指定在多久后执行某项操作。
  • 线程间的通信:在执行较为耗时的操作时,Handler负责将子线程中执行的操作的结果传递到UI线程,然后UI线程再根据传递过来的结果进行相关UI元素的更新。

对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中(这句话稍后会进行详细解释),在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。

public class TestActivity extends AppCompatActivity implements View.OnClickListener {

    Button btn1, btn2;
    TextView tv1;
    Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        tv1 = findViewById(R.id.tv1);
        btn1 = findViewById(R.id.btn1);
        btn2 = findViewById(R.id.btn2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                tv1.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");
                            }
                        });
                    }
                }).start();
                break;
            case R.id.btn2:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 延迟3S执行
                        handler.postDelayed(new Runnable() {

                            @Override
                            public void run() {
                                tv1.setText("使用Handler.postDelayed在工作线程中发送一段执行到消息队列中,在主线程中延迟3S执行。");

                            }
                        }, 3000);
                    }
                }).start();
                break;
        }
    }
}

有一点值得注意的是:对于Post方式而言,它其中Runnable对象的run()方法的代码,均运行在主线程上(虽然看上去是写在子线程当中的),如果我们在这段代码里打印日志输出线程的名字,会发现输出的是Main Thread的名字。所以对于这段代码而言,不能执行在UI线程上的操作。

Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。

public class TestActivity extends AppCompatActivity implements View.OnClickListener {

    Button btn1, btn2;
    TextView tv1;
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
                case 0:
                    System.out.println("handleMessage thread id " + Thread.currentThread().getId());
                    System.out.println("msg.arg1:" + msg.arg1);
                    System.out.println("msg.arg2:" + msg.arg2);
                    break;
                case 99:
                    System.out.println("handleMessage thread id " + Thread.currentThread().getId());
                    System.out.println("msg.arg1:" + msg.arg1);
                    System.out.println("msg.arg2:" + msg.arg2);
            }
        }

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        tv1 = findViewById(R.id.tv1);
        btn1 = findViewById(R.id.btn1);
        btn2 = findViewById(R.id.btn2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1:
                new Thread() {
                    @Override
                    public void run() {
                        //处理信息
                        try {
                            //模拟费时操作
                            System.out.println("run thread id " + Thread.currentThread().getId());
                            sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        Message msg = new Message();
                        // 也可以用下面两种方法获得Message
                        // Message msg1=Message.obtain();
                        // Message msg2=handler.obtainMessage();
                        msg.what = 0;//msg.what的类型是int型,作为msg的识别码
                        msg.arg1 = 1;//msg.arg1的类型是int型,可以传递简单的参数
                        msg.arg2 = 2;//msg.arg2的类型是int型,可以传递简单的参数
                        msg.obj = "Object类型";//msg.obj是Object型,可以传递任意参数
                        //将Message发送给handler
                        handler.sendMessage(msg);

                    }
                }.start();
                break;
            case R.id.btn2:
                new Thread() {
                    @Override
                    public void run() {
                        //处理信息
                        try {
                            //模拟费时操作
                            System.out.println("run thread id " + Thread.currentThread().getId());
                            sleep(2000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        Message msg = new Message();
                        // 也可以用下面两种方法获得Message
                        // Message msg1=Message.obtain();
                        // Message msg2=handler.obtainMessage();
                        msg.what = 99;//msg.what的类型是int型,作为msg的识别码
                        msg.arg1 = 100;//msg.arg1的类型是int型,可以传递简单的参数
                        msg.arg2 = 101;//msg.arg2的类型是int型,可以传递简单的参数
                        msg.obj = "Object类型";//msg.obj是Object型,可以传递任意参数
                        //将Message发送给handler
                        handler.sendMessage(msg);

                    }
                }.start();
                break;
        }
    }
}

log输出如下

2019-01-19 22:31:11.653 5221-5249/com.testingapp I/System.out: run thread id 245
2019-01-19 22:31:12.665 5221-5221/com.testingapp I/System.out: handleMessage thread id 2
2019-01-19 22:31:12.666 5221-5221/com.testingapp I/System.out: msg.arg1:1
2019-01-19 22:31:12.666 5221-5221/com.testingapp I/System.out: msg.arg2:2
2019-01-19 22:31:37.770 5221-5250/com.testingapp I/System.out: run thread id 246
2019-01-19 22:31:39.780 5221-5221/com.testingapp I/System.out: handleMessage thread id 2
2019-01-19 22:31:39.780 5221-5221/com.testingapp I/System.out: msg.arg1:100
2019-01-19 22:31:39.781 5221-5221/com.testingapp I/System.out: msg.arg2:101
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值