Handler机制

学习视频(推荐慕课网视频)https://www.imooc.com/video/5519

1、是什么

是android提供的用来更新UI的一套机制,也是一套消息处理的机制

2、怎么用

a、通过sendMessage()方法(其内部调用sendMessageDelayed)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView textView;

    //1、创建Handler
    private  Handler handler ;

    @SuppressLint("HandlerLeak")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.text);

        findViewById(R.id.button).setOnClickListener(this);


        //2、实现handlerMessage()方法
        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                textView.setText(msg.obj.toString());
            }
        };
    }

    @Override
    public void onClick(View v) {

        new Thread(){
            @Override
            public void run() {
                
                //3、创建一个Message,通过new或者使用Message.Obtain()方法
                Person person = new Person("张三",44);
                Message message = new Message();
                message.obj = person;
                
                //4、调用sendMessage方法发送消息
                handler.sendMessage(message);
            }
        }.start();
    }
}

b、通过post()方法(其内部也是调用sendMessageDelayed)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView textView;

    //1、创建Handler
    private  Handler handler = new Handler();

    @SuppressLint("HandlerLeak")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.text);

        findViewById(R.id.button).setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {

        new Thread(){
            @Override
            public void run() {


                //调用post方法
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("update Thread");
                    }
                });
            }
        }.start();
    }
}

3、原理

Handler机制
Message:消息,可通过new Message()或者Message.obtain获得(推荐使用Message.obtain()来获取Message实例,因为在Message类里面定义了一个消息池,当消息池里存在未使用的消息时,便返回,如果没有未使用的消息,则通过new的方式创建返回,所以使用Message.obtain()的方式来获取实例可以大大减少当有大量Message对象而产生的垃圾回收问题。)

MessageQueue:消息队列(这里有必要提一下MessageQueue的数据结构,是一个单向链表,Message对象有个next字段保存列表中的下一个,MessageQueue中的mMessages保存链表的第一个元素。)

Looper:每一个线程只有一个Looper,每个线程在初始化Looper之后,然后Looper会维护好该线程的消息队列,用来存放Handler发送的Message,并处理消息队列出队的Message。

不管post还是sendMessage方法,最后的本质都是一样的,因此以sendMessage为例介绍整个流程:子线程调用sendMessage方法,经过内部一系列函数调用,将Message对象添加到Looper创建的MessageQueue队列中,同时给Message指定了target对象(Handler),此时,Looper.loop()方法从Looper的成员变量MessageQueue队列中调用Message的target对象的dispatchMessage方法(也就是msg.target.dispatchMessage方法)取出Message,然后在dispatchMessage方法中调用Message的target对象的handleMessage()方法(也就是msg.target.handleMessag)

源码:
Handler、Looper、MessageQueue如何关联:

Handler.Handler():通过Looper.myLooper()获得Looper
Handler机制
Looper.myLooper():通过sThreadLocal.get()获得Looper的,(关于ThreadLocal:不同的线程访问同一个ThreadLocal,不管是get方法还是set方法对其所做的操作,仅限于各自线程内部。这就是为什么用ThreadLocal来保存Looper,因为这样才能使每一个线程有单独唯一的Looper。)
Handler机制
Looper.perpare():通过new Looper创建Looper,并通过sThreadLocal.set方法保存Looper
Handler机制

4、Handler引起的内存泄漏

原因:handler非静态内部类持有外部类的匿名引用,导致外部类无法被回收

解决办法:handler内部持有外部Activity的弱引用,并把handler改为静态内部类,然后在onDestroy方法中调用handler的removeCallBack()方法