Android之Handler原理解析

本文详细介绍了Android中Handler的作用和使用方法,包括如何通过Handler在子线程中更新UI,以及Handler、MessageQueue和Looper的工作原理。文章强调了使用Handler时防止内存泄露的重要性,提供了两种解决方案,即使用静态内部类和弱引用,以及在Activity销毁时清理Handler的消息队列。
摘要由CSDN通过智能技术生成

Handler定义

Handler 是一个消息分发对象,是Android给我们提供用来更新UI的一套机制。简单来说,子线程是不可以直接更新Android的UI布局的,子线程要更新UI布局的话,就得经过Handler机制和UI线程通讯以完成UI布局的更新。

Handler简单使用

1、首先定义一个静态内部类

public class MainActivity extends AppCompatActivity {
	//其他代码已经省略...
	
	private static class MyHandler extends Handler{
        // 定义 弱引用实例
        private WeakReference<Activity> reference;
        // 在构造方法中传入需持有的Activity实例
        public MyHandler(Activity activity) {
            // 使用WeakReference弱引用持有Activity实例
            reference = new WeakReference<Activity>(activity); }

        // 通过复写handlerMessage() 从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            	//这里是接受信息并处理信息
                case 1:
                    break;
                case 2:
                    break;
            }
        }
    }
}

2、使用过程

MyHandler mHandler;
//初始化了一个MyHandler
public void initHandler(){
    Looper.prepare();//在ui线程中,不需要这行代码
    mHandler = new MyHandler(this);
    Looper.loop();//在ui线程中,不需要这行代码
}
//子线程可以开始通过mHandler发送数据了
public void childTreadSendMsgToHandler() {
    new Thread() {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // a. 定义要发送的消息
            Message msg = Message.obtain();
            msg.what = 1;// 消息标识
            msg.obj = "AA";// 消息存放
            mHandler.sendMessage(msg);
        }
    }.start();
}

原理解析

注意!这篇文章的源码解析是基于Android SDK 28
看下Looper.prepare()

public static void prepare() {
    prepare(true);
}
private static void prepare(boolean quitAllowed) {
	/*
	sThreadLocal是啥?
	static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
	如果该线程下的对应的Looper已经创建了,则会抛出runtimeexception
	*/
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //为该线程创建一个Looper对象
    sThreadLocal.set(new Looper(quitAllowed));
}

Looper.prepare()这个函数比较简单,就是查询当前线程下是否已经创建Looper对象了,如果已经创建了就抛出RuntimeException;如果没有创建,就创建。这里的Looper对象是使用了ThreadLocal来维护的,可见Looper和线程是一一对应的关系,就是一个线程里面最多只有一个Looper。
看一下Looper的构造函数new Looper(quitAllowed)

private Looper(boolean quitAllowed) {
     mQueue = new MessageQueue(quitAllowed);
     mThread = Thread.currentThread();
 }

Looper的构造过程也比较简单,就是初始化了一个MessageQueue(消息队列),然后获取当前线程。
看一下初始化Handler的构造函数

public Handler() {
    this(null, false);
}
public Handler(Callback callback, boolean async) {
	/*
	FIND_POTENTIAL_LEAKS是啥
	private static final boolean FIND_POTENTIAL_LEAKS = false;
	FIND_POTENTIAL_LEAKS初始值为false
	*/
    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());
        }
    }
	//获取当前线程对应的Looper对象
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    //获取Looper中的mQueue
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Handler的初始化过程也比较简单,获取Looper中的消息队列,初始化mCallback 、mAsynchronous。
接着看Looper.loop()

public static void loop() {
//仅仅留下了部分代码...

	//获取到当前线程对应的Looper
    final Looper me = myLooper();
    //如果当前线程的Looper为null,抛出异常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获取到Looper中的消息队列
    final MessageQueue queue = me.mQueue;
    
	//死循环
    for (;;) {
    	//不断地冲queue中拿消息,会阻塞
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            //消息为null,说明消息队列停止了,直接return
            return;
        }
		...省略部分代码...
		//msg.target就是一个handler,开始想msg中的handler分发msg
		msg.target.dispatchMessage(msg);
		
		...省略部分代码...
    }
}

读源码到这里,明白了Looper是干嘛的。looper就是一个死循环,不断地调用queue.next()获取里面的msg,然后把msg分发给msg.target(msg.target.就是该msg对应的handler)
看一下msg.target.dispatchMessage(msg)

public void dispatchMessage(Message msg) {
     if (msg.callback != null) {
         handleCallback(msg);
     } else {
         if (mCallback != null) {
             if (mCallback.handleMessage(msg)) {
                 return;
             }
         }
         handleMessage(msg);
     }
 }

dispatchMessage最终会调用handleMessage(msg),handleMessage就是我们自己重写的那个handleMessage函数了。
看到这里,handler基本工作原理也差不多明白了。

总结

Handler机制就是由MessageQueue(消息队列)、Looper(循环器)、Handler。MessageQueue中消息队列存放的是一个一个Message,这些Message是通过Handler对象传过来的,并且里面包装有对应的Handler对象(msg.target)。首先Looper.prepare()会为当前线程初始化一个Looper(一个线程最多对应一个Looper),Looper就是一个循环器,底层使用死循环不断地调用queue.next()来获取消息队列中的msg,然后分发msg(回调msg中的handler中的handleMessage方法)。

使用Handler的注意事项

1、使用Handler不恰当会容易照成内存泄露问题。
如果把static去掉,把WeakReference换成强引用,使用过程中容易造成内存泄露问题。

public class MainActivity extends AppCompatActivity {
	//其他代码已经省略...
	
	private class MyHandler extends Handler{

        public MyHandler() {}

        // 通过复写handlerMessage() 从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            	//这里是接受信息并处理信息
                case 1:
                    break;
                case 2:
                    break;
            }
        }
    }
}

为什么会造成内存泄露问题呢?
因为MyHandler是MainActivity的内部类,内部类MyHandler会持有外部类的引用的。如果MainActivity调用了finish,MainActivity其实就是已经需要被GC的了,但是有可能MyHandler还有一些任务没有处理完,导致还持有MainActivity的引用,所以导致MainActivity虽然是无用的对象了,但是因为被其他对象给引用,所以无法被GC,导致了内存泄露。
解决方案
方案1
把MyHandler申明为静态内部类,用WeakReference来引用需要关联的Activity。原因:静态内部类不会持有外部类的引用,弱引用WeakReference不会影响引用对象的生命周期。

public class MainActivity extends AppCompatActivity {
	//其他代码已经省略...
	
	private static class MyHandler extends Handler{
        // 定义 弱引用实例
        private WeakReference<Activity> reference;
        // 在构造方法中传入需持有的Activity实例
        public MyHandler(Activity activity) {
            // 使用WeakReference弱引用持有Activity实例
            reference = new WeakReference<Activity>(activity); }

        // 通过复写handlerMessage() 从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            	//这里是接受信息并处理信息
                case 1:
                    break;
                case 2:
                    break;
            }
        }
    }
}

方案2
在外部Activity的onDestroy中把Handler中的队列清空以结束Handler生命周期

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
    // 外部类Activity生命周期结束时,同时清空消息队列 & 结束Handler生命周期
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值