Handler机制的理解与使用

一、为什么要用Handler

当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响应用户并分发事件等。所以一般在主线程中不要执行比较耗时的操作,如联网下载数据等,否则出现ANR(应用无响应)错误。所以就将这些操作放在子线程中,但是由于Android子线程是不安全的,所以只能在主线程中更新UI。Handler就是用来 子线程和创建Handler的线程进行通信的。

二、理解Handler机制的使用

开始今天的学习之前,我们先来了解一些概念:
Android是消息驱动的,实现消息驱动有几个要素:

消息的表示:Message
消息队列:MessageQueue
消息循环:用于循环取出消息进行处理:Looper
消息处理:消息循环从消息队列中取出消息后要对消息进行处理:Handler
handler类有两种主要用途:
1、按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。
2、把一个对另外线程对象的操作请求放入消息队列中,从而避免线程间冲突。

这里写图片描述

三、Handler机制的使用

Handler工具类在多线程中有两方面的应用:

1、发送消息,在不同的线程间发送消息,使用的方法为sendXXX();
android.os.Handler对象通过下面的方法发送消息的:
sendEmptyMessage(int),发送一个空的消息;
sendMessage(Message),发送消息,消息中可以携带参数;
sendMessageAtTime(Message, long),未来某一时间点发送消息;
sendMessageDelayed(Message, long),延时Nms发送消息。

2、计划任务,在未来执行某任务,使用的方法为postXXX();
android.os.Handler对象通过下面的方法执行计划任务:
post(Runnable),提交计划任务马上执行;
postAtTime(Runnable, long),提交计划任务在未来的时间点执行;
postDelayed(Runnable, long),提交计划任务延时Nms执行。

下面我们用代码来实现:
1、使用Message消息
这里写图片描述

public class HandlerActivity extends AppCompatActivity implements View.OnClickListener {
    TextView textHandler;
    Button buttonMessage, buttonRunnable;
    Handler handler;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        textHandler = (TextView) findViewById(R.id.text_handler);
        buttonMessage = (Button) findViewById(R.id.button_message);
        buttonRunnable = (Button) findViewById(R.id.button_runnable);
        buttonMessage.setOnClickListener(this);
        buttonRunnable.setOnClickListener(this);
        handler = new MyHandler();
    }


    public class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    Log.e("测试", String.valueOf(msg.arg1 + msg.arg2));
                    textHandler.setText(msg.obj.toString());
                    break;
            }
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_message:
                //使用Message的方式传递消息
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = handler.obtainMessage();
                        message.arg1 = 1;
                        message.arg2 = 2;
                        message.obj = "小米";
                        message.what = 1;
                        message.sendToTarget();
//                也可以使用这种方式发送message
//                handler.sendMessage(message);
                    }
                }).start();
                break;
            case R.id.button_runnable:
                //使用Runnable的方式传递消息
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                //这句话其实是在创建handler的线程中执行的,这是则是在主线程中运行的
                                //说明只是把runnable里的run方法放到UI线程里运行,并不会创建新线程
                                //因此我们可以在子线程中将runnable加入到主线程的MessageQueue,然后主线程将调用runnable的方法,可以在此方法中更新主线程UI。
                                textHandler.setText("小米2");
                            }
                        });
                    }
                }).start();
                break;

        }


    }
}

2、使用Runnable传递
写在上面代码中!

四、在线程中创建Handler传递消息,还有HandlerThread的使用

如何在线程当中实例化Handler。在线程中实例化Handler我们需要保证线程当中包含Looper(注意:UI-Thread默认包含Looper)。
为线程创建Looper的方法如下:在线程run()方法当中先调用Looper.prepare()初始化Looper,然后再run()方法最后调用Looper.loop(),这样我们就在该线程当中创建好Looper。(注意:Looper.loop()方法默认是死循环)。
我们实现Looper有没有更加简单的方法呢?当然有,这就是我们的HandlerThread。我们来看下Android对HandlerThread的描述:
—Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

Handler机制的分发中心就在Looper中的loop(),HandlerThread将loop转到子线程中处理,降低了主线程的压力,使主界面更流畅,其实 说白了,创建HandlerThread,只是为了用此线程的looper  最终的runnable都还是post到主线程运行(已用Toast测试过)

使用步骤

尽管HandlerThread的文档比较简单,但是它的使用并没有想象的那么easy。

1、创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread(“HandlerThread”);
handlerThread.start(); //创建HandlerThread后一定要记得start()

2、获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();

3、创建Handler,通过Looper初始化
Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。

如果想让HandlerThread退出,则需要调用handlerThread.quit();

public class HandlerActivity extends AppCompatActivity implements View.OnClickListener {
    Button  threadHandler, handlerThread;
    Handler threadHanlder;
    Handler hanlderThread;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        threadHandler = (Button) findViewById(R.id.button_thread_handler);
        handlerThread = (Button) findViewById(R.id.button_handlerthread);
        threadHandler.setOnClickListener(this);
        handlerThread.setOnClickListener(this);
        //使用子线程中创建Handler
        ThreadHandler threadHandler = new ThreadHandler();
        threadHandler.start();
        //创建HandlerThread
        HandlerThread handlerThread = new HandlerThread("hanlderThread");
        handlerThread.start();
        hanlderThread = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 2:
                        Log.e("HandlerThread", Thread.currentThread().toString());
                        break;
                }
            }
        };
        Log.e("MianThread", Thread.currentThread().toString());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_thread_handler:
                threadHanlder.sendEmptyMessage(1);
                break;
            case R.id.button_handlerthread:
                hanlderThread.sendEmptyMessage(2);
                break;
        }

    }

    //使用子线程实现Hanlder
    public class ThreadHandler extends Thread {
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            threadHanlder = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case 1:
                            Log.e("ThreadHandler", Thread.currentThread().toString());
                            break;
                    }
                }
            };
            Looper.loop();
        }
    }
}

布局:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值