Handler机制的理解与使用

来源:互联网 发布:人工智能大学专业 编辑:程序博客网 时间:2024/05/22 11:47

一、为什么要用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();        }    }}

布局:
这里写图片描述

0 0