Handler面试知识小结

前言

今天我们来回顾复习下Handler,处于性能优化的考虑,Android的UI线程是线程不安全的。为了避免多个线程并发操作UI的引发UI显示错乱问题,Android指定只允许在UI线程修改更新UI组件。其他线程更新UI抛出android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.异常,当我们在子线程做完耗时操作时,需要更新UI时,我们就需要通过Handler来实现啦。

1、Handler是什么?

1、Handler通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。

2、线程之间通信。

2、Handler使用方法

  • post(runnable)

  • sendMessage(message)

3、Handler工作原理

handler1
这里写图片描述

  • Handler: 负责发送消息和处理消息。
  • Looper: 负责管理MessageQueue,从MessageQueue中取出消息,交给消息对应的Handler处理。一个线程只有一个Looper对象。
  • Message: Handler接收处理的消息对象。
  • MessageQueue: 消息队列,负责管理Message, 先进先出。程序创建Looper对象时,会在他的构造器里创建MessageQueue对象。

总结:

1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。

2、Looper.loop()会让当前线程进入一个无限循环,不断从MessageQueue的消息队列中读取消息,然后回调msg.target.dispatchMessage(msg)方法。

3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue相关联。

4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。

5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

4、Handler引起的内存泄漏

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

  • 解决:

    • Handler内部持有外部Activity的弱引用。
    • Handler改为静态内部类。
    • Handler.removeCallback()。

5、代码实践

第1种在UI线程创建Handler,子线程发送消息,UI线程收到消息进行处理:

由于在Activity的启动代码中在当前UI线程调用了Looper.prepare()和Looper.loop()方法,所以我们在Activity创建Handler就可以了,详情我们可以查看ActivityThread类的main 方法中,我们就会发现调用了Looper.prepareMainLooper()和Looper.loop()方法。

ActivityThread创建Looper的系统源码:

public final class ActivityThread {
    public static void main(String[] args) {
    // 省略部分代码
         //prepareMainLooper()方法中调用了Looper.prepare(false); 创建出Looper对象
        Looper.prepareMainLooper();
        // 开始轮询
        Looper.loop();
        // 如下代码我们发现在UI线程我们不能手动调用停止Loop,不然会抛异常。
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}

例子:在子线程发送消息在UI线程弹出Toast具体代码:

package com.example.ling.review.handler;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.example.ling.review.R;

import java.lang.ref.WeakReference;

public class HandlerActivity extends AppCompatActivity {

    private Handler mHandler = new MainHandler(this);

    // Handler改为静态内部类,避免内存泄漏
    public static class MainHandler extends Handler {

        private WeakReference<HandlerActivity> mWeakReference = null;

        public MainHandler(HandlerActivity activity) {
            // 将Activity 包装成弱引用,避免内存泄漏
            mWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            // 接收处理消息
            HandlerActivity activity = mWeakReference.get();
            if (activity != null) {
                Toast.makeText(activity, "我在UI线程上哦", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        initView();
    }

    private void initView() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    // 第一种 post(runnable)用法
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(getApplicationContext(), "我在UI线程上哦", Toast.LENGTH_SHORT).show();
                        }
                    });

                    // 第二种 sendMessage(message)用法
                    Thread.sleep(2000);
                    Message message = Message.obtain();
                    mHandler.sendMessage(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        // activity 销毁时 Handler 移除所有回调和信息
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }
}

第2种子线程创建Handler,在子线程发送消息,创建Handler的子线程中接收到消息进行处理:

 1、子线程使用Handler需要自己创建Looper对象;
 2、Looper创建完,在创建Handler对象;
 3、开启Looper轮询,Handler就可以发送、处理消息啦;

例子:


public class HandlerActivity2 extends AppCompatActivity {

    private ThreadHandler mHandler;

    // Handler改为静态内部类,避免内存泄漏
    public static class ThreadHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            // 接收处理消息
            Log.d("TAG", "接收消息啦----- 当前线程为:" + Thread.currentThread().getName());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        newThread1();
        newThread2();
    }

    /**
     * 创建子线程1 创建Handler
     */
    private void newThread1() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("TAG", "当前线程为:" + Thread.currentThread().getName());
                // 1、创建Looper
                Looper.prepare();
                // 2、创建Handler
                mHandler = new ThreadHandler();
                // 3、Looper开始轮询
                Looper.loop();
            }
        }).start();
    }

    /**
     * 创建子线程2 用子线程1的handler 发送消息
     */
    private void newThread2() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.d("TAG", "当前线程为:" + Thread.currentThread().getName());
                    Thread.sleep(2000);
                    Message message = Message.obtain();
                    mHandler.sendMessage(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        // activity 销毁时 Handler 移除所有回调和信息
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }
}

运行打印结果如下:
我们发现在Thread-2子线程创建了Handler, 在Thread-3子线程发送消息,接收到消息在Thread-2 子线程。

这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章