Android知识体系总结2020之Android部分Handler篇

江枫思渺然 提交于 2020-04-06 22:02:22

 

1.什么是Handler?

  Handler是可以通过发送和处理Message和Runnable对象来关联相应线程的MessageQueue。通常我们认为它是一种异步机制。

  a.可以让对应的Message和Runnable在未来的某个时间点进行相应的处理。

  b.让自己想要的耗时操作在子线程中完成,让更新UI的操作在主线程中完成,而子线程与主线程之间的通信就是靠Handler来完成。

2.Handler的使用方法

  Handler提供了很多异步机制的方法,只不过我们常用就只有post和sendMessage系列方法,我们先来看看Handler提供的构造器吧:

  • Handler():默认构造函数将此处理程序与Looper用于当前线程。
  • Handler(Handler.Callback callback):构造函数将此处理程序与Looper对于当前线程,并接受一个回调接口,您可以在其中处理消息。
  • Handler(Looper looper):使用所提供的Looper而不是默认的。
  • Handler(Looper looper, Handler.Callback callback):使用所提供的Looper而不是默认的,而是接受一个回调接口来处理消息。

  接下来我们就来看看Handler提供的各种方法吧:

  • post(Runnable r):导致将Runnable r添加到消息队列中。
  • postAtTime(Runnable r, long uptimeMillis):使Runnable r添加到消息队列,并在uptimeMillis.
  • postDelayed(Runnable r, long delayMillis):使Runnable r被添加到消息队列,并在指定的时间流逝后运行。
  • removeCallbacks(Runnable r):删除消息队列中所有可运行的Runnable消息任务。
  • removeMessages(int what):删除消息队列中消息对象what字段为"what"的消息任务。
  • sendEmptyMessage(int what):发送一个空消息对象,并设置这个空消息的what值。
  • sendEmptyMessageAtTime(int what, long uptimeMillis):发送只包含要在特定时间传递的值的消息。
  • sendEmptyMessageDelayed(int what, long delayMillis):发送一条消息,该消息只包含要在指定的时间间隔后传递的值。
  • sendMessage(Message msg):将消息推送到消息队列的末尾,在当前时间之前完成所有挂起的消息。
  • sendMessageAtTime(Message msg, long uptimeMillis):在所有挂起的消息在绝对时间之前uptimeMillis(以毫秒为单位)之前,将消息放入消息队列中。
  • sendMessageDelayed(Message msg, long delayMillis):在所有挂起的消息之前(当前时间+delayMillis)之后,将消息放入消息队列中。

3.Handler内部的实现机制

  面试的时候,Handler的原理问到的概率还是蛮大的,不光只是为了面试,我们好好去了解一下Handler的原理,那么对于我们去使用Handler而言是非常有好处的,至少我们知道我们发送的消息如何发送到了UI线程的,当出现问题时,我们只要小小一分析便会知道问题发生于何处,然后解决它,好了,闲话不多扯了,下面来介绍Handler机制的实现原理。
  Handler机制也可叫异步消息机制,它主要由4个部分组成:Message,Handler,MessageQueue,Looper,在上面我们已经接触到了Message和Handler,接下来我们对4个成员进行着重的了解:

1.Message
  Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。

2.Handler
  Handler顾名思义就是处理者的意思,它只要用于在子线程发送消息对象Message,在UI线程处理消息对象Message,在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,最终在handleMessage方法中消息对象Message被处理。

3.MessageQueue
  MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。每个线程中只会有一个MessageQueue对象,请牢记这句话。其实从字面上就可以看出,MessageQueue底层数据结构是队列,而且这个队列只存放Message对象。

4.Looper
  Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。每个线程只有一个Looper对象。

  了解了上述Handler机制的4个成员后,我们再来把思路理一遍:首先在UI线程我们创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UIi线程的逻辑处理,接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这个Message实例对象发送出去,之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法,最终前面提到的消息会被Looper从MessageQueue中取出来传递给handleMessage方法,最终得到处理。这就是Handler机制整个的工作流程,怎么样?你懂了吗?看看下面的图你就更懂了:

Handler机制工作流程图

以下从源码角度去了解Handler的原理: http://blog.csdn.net/u012827296/article/details/51236614

4.Handler引起的内存泄漏以及解决方法

原因:非静态内部类持有外部类的匿名引用,导致外部activity无法得到释放。

解决方法:handler内部持有外部的弱引用,并把handler改为静态内部类,在activity的onDestory()中调用handler的removeCallback()方法。

http://blog.csdn.net/javazejian/article/details/50839443

5.如何使用Handler让子线程与子线程之间进行通信?

  如今的面试,Handler基本上很多面试者都会流畅的说出来,但是如果想要给面试官亮点,那就需要我们对Handler了解的十分透彻,我们通常代码中是子线程与主线程进行异步通信,那么子线程与子线程之间也可以吗?当然可以,只不过我们需要对Looper足够了解,深入研究Hanlder你可以看笔者Handler源码分析部分。那么我们如果需要子线程A和子线程B之间进行Handler通信,而且是子线程A向子线程B发送消息,那么我们应该怎样做呢?

public class MainActivity extends AppCompatActivity {

    private Handler threadHandler;

    [@Override](https://my.oschina.net/u/1162528)
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    class ThreadA extends Thread{

        [@Override](https://my.oschina.net/u/1162528)
        public void run() {
            super.run();
            Looper.prepare();

            threadHandler = new Handler(){

                [@Override](https://my.oschina.net/u/1162528)
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //收到来自于ThreadB的消息,注意这里运行在ThreadA线程中
                
                    //......
                }
            };

            Looper.loop();

        }
    }

    class ThreadB extends Thread{

        [@Override](https://my.oschina.net/u/1162528)
        public void run() {
            super.run();

            Looper looper = Looper.myLooper();

            Message message = new Message();
            message.obj = "ThreadB发送消息到ThreadA";
            //......
            threadHandler.sendMessage(message);



        }
    }




}

  笔者写的这份代码也许不好,但是没有关系,我们只需要学会其中几个关键的地方,如何让ThreadB往ThreadA中发送消息,首先你得在ThreadA中准备一个Looper,也就是消息轮询大管家,然后准备发送消息的Handler,准备发送消息的Handler很容易理解,那就是在ThreadA中生成一个Handler对象即可, 那么准备Looper怎么做呢?在ThreadA中调用Looper.prepare(),然后再调用Looper.loop()即可,为什么要这么调用呢?我们怎么没有在UI主线程看到这样调用的代码呢?其实它们的调用在源码里面,我们并没有看到,因此为了非常熟悉Handler机制,我们需要去研究研究Handler的源码,这样我们才会知道笔者这里的代码为什么这么写才能让ThreadB线程往ThreadA线程发送消息从而达到子线程与子线程进行Handler异步通信的目的。

6.Android原生基于Handler封装的轮子

AsyncTask
HandlerThread
IntentService

7.Handler原理解析(从底层角度)

待总结

面试题(检测自己学的怎么样)

  • 1.子线程一定不能更新UI吗?(校招&实习)
  • 2.给我说说Handler的原理(校招&实习)
  • 3.Handler导致的内存泄露你是如何解决的?
  • 4.如何使用Handler让子线程和子线程通信?
  • 5.你能给我说说Handler的设计原理?
  • 6.HandlerThread是什么 & 原理 & 使用场景?
  • 7.IdleHandler是什么?
  • 8.一个线程能否创建多个Handler,Handler和Looper之间的对应关系?
  • 9.为什么Android系统不建议子线程访问UI?
  • 10.Looper死循环为什么不会导致应用卡死?
  • 11.使用Handler的postDealy后消息队列有什么变化?
  • 12.可以在子线程直接new一个Handler出来吗?
  • 13.Message对象创建的方式有哪些 & 区别?
  • 14.ANR和Handler存在什么联系吗?
  • 15.子线程的Looper和主线程的Looper有什么区别?
  • 16.说说Handler为什么不能进行跨进程通信?
  • 17.Handler的消息延时是如何实现的?
  • 18.什么是消息屏障?
  • 19.假设主线程new了Handler A和Handler B以及Handler C,现在有个子线程,在子线程中通过Handler C发送了一条消息,那么Handler A和Handler B能接收到吗?为什么?

注意:文章末尾面试题来自于笔者自己总结,想求答案或者交流,start 笔者GitHub项目AndroidFaceInterview

更新时间:2020-01-15

推荐:公司LOGO设计

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!