对Handler的理解以及使用

前言

相信大家初学Android一定写过这样的代码:

1、在onCreate方法中:先发送网络请求,将得到的数据赋给一个String对象,然后接着就用一个TextView来显示这个数据

2、后来搞懂了不能在主线程发送网络请求,那好,在子线程当中发送网路请求得到数据以后,直接在子线程中更新UI

那当然了,这两种情况都是行不通的,当时还特别的纳闷怎么回事。。。

Handler机制的理解

相信大家对Handler不陌生吧,在Android开发时,Handler是很常用的,那我们好好的回顾一下

在Android开发中,规定只有UI线程,也就是主线程能进行UI更新的操作,比如说网络请求这种耗时操作就只能在子线程当中进行了,那我们很多时候需要把从网络请求来的数据显示到UI界面上,那这就需要用到异步了,那么Handler是其中一种比较常用的方式,那我们说一下他们之间的关系吧:

主线程:应用程序第一次启动时,就会开启一条主线程,处理UI更新

子线程:我们人为开启的线程,执行耗时操作比如说网络请求等

Message:线程间通讯的数据单元,存放数据

MessageQueue:存储Handler发送来的消息

Handler:意为处理者,发送消息,处理更新UI的操作

Looper:意为循环器,MessageQueue和Handler的媒介

大体说一下整个流程吧:

在启动一个Activity时,也就是启动了一个主线程的时候,

会默认自动创建一个Looper和MessageQueue对象,然后Looper自动进入到消息循环,

然后我们创建了Handler,Handler会自动绑定主线程的Looper和MessageQueue对象,

当我们在子线程中发送网络请求后得到了数据,将数据放入Message中,然后通过Handler的sendMessage方法发送到MessageQueue当中

Looper循环取出MessageQueue中的消息,然后将消息分发给Handler

最后handler根据分发过来的Message中的内容进行UI操作

 

看了这么多一定云里雾里的,我给大家做个比喻吧,来一张图:

对Handler的理解以及使用_第1张图片

我们要做一个大型的画展,现场作画

舞台(主线程)只负责展示大家的画作(更新UI),

幕后作画(子线程)是画家进行创作过程(网络请求下载等耗时操作),

画作(Message)是作画完成后由工作人员打包好的,

用于暂时存放画作的箱子(MessageQueue),

工作人员团队(Handler)

观察员(looper)

好了,画展开始举办了,首先我们看到的是舞台(启动了主线程),观察员和放画的箱子第一个先就位了(自动创建Looper和MessageQueue对象),观察员自画展开始就一直在时刻关注箱子里有没有画作(实际并不是这样进行无脑操作),然后画家们开始作画了(子线程发送网络请求),谁完成了画作(得到了数据),就把作品交给工作人员,工作人员发送到箱子内(handler .sendMessage),然后观察员看到箱子内有作品了,把作品取出来安排给工作人员让他把作品送到舞台上面,展示给大家(在handlerMessage中进行UI操作)。

注意,一个画展只有一个观察员,但是观察员手底下可以有好几个工作人员团队。

一个线程只能绑定一个Looper,但可以有多个Handler。

Handler的使用

1、布局文件




    

2、新建Handler的子类,采用内部类的方式(我们还可以采用匿名内部类)

 class Mhandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    textView.setText(msg.obj.toString());
                    break;
                default:
                    break;
            }
        }
    }

3、创建Handler对象

    private TextView textView;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.text_view);
        handler = new Mhandler();
        sendRequest();
    }

4、模拟发送网络请求

 private void sendRequest(){
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //创建一个Message实例,
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = "得到了某网站返回的数据,并更新了UI";
                handler.sendMessage(msg);
            }
        }.start();
    }

运行结果:

对Handler的理解以及使用_第2张图片                 对Handler的理解以及使用_第3张图片

Handler有两种方式,上面用的是handler.sendMessage()的方式

还有一种handler.post(),就是用法不一样,要在子线程new一个Runnable,不用重写handlerMessage()方法

 new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 通过psot()发送,传入1个Runnable对象
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // 指定操作UI内容
                        mTextView.setText("得到了某网站返回的数据,并更新了UI");
                    }

                });
            }
        }.start();

小Demo地址:https://github.com/pengboboer/HandlerTest

总结

Handler的理解和用法大致就是这样,可能我写的比较粗浅,但是也够初学者理解Handler机制,自己也记录下来,大家多多包涵。当然,上面这个例子是会存在内存泄漏风险的,非静态内部类和匿名内部类会默认持有外部类的引用。

我发现一个大神写的不错,分析Handler源码的,篇幅比较大,大家如果想深入了解可以看一下:

https://blog.csdn.net/carson_ho/article/details/80388560

好了,就是这样。晚安~

你可能感兴趣的:(Android基础)