Handle初解,看完你就懂了handle


前言

提示:看完本篇,你可以了解到Handle的相关知识与常见的误区提醒


一、Handle是什么?

我们查看一下谷歌官方对其的定义:
A Handler allows you to send and process {@link Message} and Runnable
objects associated with a thread’s {@link MessageQueue}. Each Handler
instance is associated with a single thread and that thread’s message
queue. When you create a new Handler, it is bound to the thread /
message queue of the thread that is creating it – from that point on,
it will deliver messages and runnables to that message queue and execute
them as they come out of the message queue.

Handler它可以通过消息队列发送消息或者runable对象,也可以处理消息或者runable对象。每一个handler实例,都持有一个线程以及此线程的消息队列。
那么handle相当于什么呢?其实就相当于我们现实世界的搬运工,可以发送消息,也可以处理消息。

二、Handle有啥用呢?

1.传递消息到ui线程

在我们安卓开发的时候,我们都知道ui线程是不可以进行耗时操作的,如果在这里进行的话,就会导致ANR,因此开辟一个子线程,在子线程中去处理相关的耗时任务,这是必然的结果。那么处理完的结果需要改变ui,即我们的控件显示的时候怎么办呢?在子线程中处理完直接改变ui是安卓中不允许的行为,因为ui线程不是线程安全的,那么我们有必要需要一个工具将子线程处理的结果带回去给ui线程去显示,而handle正是完成了这个任务。

2.代码示例

主线程定义一个handle(mHandle),构造方法里面new一个callback,复写handleMessage方法,这
就表明当有信息来的时候,由handleMessage方法去执行
      mHandler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message msg) {
                //处理消息
                if(msg.what == 1) {
                    Log.d("hanldeTest","object is -- > " + msg.obj);
                }
                return false;
            }
        });
子线程中,假设处理完了一些耗时操作,比如读写数据库,随后即可执行一下代码
Message message = mHandler.obtainMessage();
        message.what = 1;
        message.obj = "我是新消息!";
        mHandler.sendMessage(message);

这样子一个发送,一个接受,就完成了就基本的handle使用,值得注意的是,上诉方法已经过期了
在这里插入图片描述
下面是最新的使用方法:

        boolean test=new Handler(getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
              //更新ui处理,在耗时任务完成后
            }
        });

这里细心观察的小伙伴就会发现,参数里面有一个getMainLooper(),字面意思就是获得主looper对吧,那么looper是个啥?拿了有啥用?我们先以过期的方法去解释更方便
handle源码:

    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这里有个值得的两个对象,mLooper,mQueue。当系统创建一个ActivityThread的时候,也创建了一个Looper,在looper里面有一个消息队列(其实是单链表结构的东西),Looper负责不断循环保持我们的程序不会结束,queue则负责接受消息,然后有handle去处理。我们一个线程只有一个looper,负责当前线程的不中断,但是handle可以有多个,所有的handle都依附于某个消息队列(没有队列你要搬运工干嘛对吧),而队列由looper创建,这也相当于handle间接依赖于looper了嘛~(看源码mQueue = mLooper.mQueue;)
因为系统一开始就创建好ui线程的时候也自动帮我们创建好了looper,也所以我们在主线程创建的时候可以不用关心handle具体依附于哪个looper。
但是如果在子线程中呢?子线程则没有这样好的待遇,它没有自动生成looper,所以我们在普通子线程中创建handle不指定好特定的looper就会报错,因为handle要好好依赖于一个消息队列,而消息队列由我们的looper产生的嘛~因此就有了new Handler((放一个looper过来!))这个方法,如
new Handler(getMainLooper())。

3注意点

下面说一下几个注意点,我在面试的时候看到面试官也会问错的问题。handle是如何实现异步的?
可能有的同学就会说,异步?就创建一个子线程啊!其实handle,runnable之类的并不会创建一个新线程!

1、handle可以在主线程中创建,而正在使用发送信息是在子线程,而不是handle自己new了一个子线程
2、handle创建的时候依赖于传入的looper,如果传入的looper是ui线程的looper,那么当在子线程调用的时候,handle发送的消息也是发送到ui线程的消息队列里面,由消息队列取出来再处理,所以才会有这样一个异步的操作。线程的looper一直在调用.loop方法,去查询消息队列有没有东西,有的话就取出来。
源码如下

public static void loop() {
        final Looper me = myLooper();
		
		......
		
		//开始轮询,这个轮询可能阻塞
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
			
			......
			
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
			
			......
			
            msg.recycleUnchecked();
        }
    }

最后

看到这里你应该对handle处理消息是如何进行的吧,感谢各位看官~

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值