如何形象地理解Handler

What Is Handler

从开发者的角度而言,Handler是Android消息机制的上层接口,用于进程内不同线程之间的通信。(可以了解下线程间通信的常用方式)

What’s Handler Use For

更新UI:
我们在日常开发种,用的最多的便是利用Handler来更新UI(注意,在子线程种更新UI是不准确的说法)。可以了解一下Handler的其它用处

UI操作验证

void checkThread(){
	if( mThread != Thread.currentThread() ){ 
		throw new calledFormWrongThreadExeception (
		“Only the original thread that created a view hirrarchy can touch its views .)
}

How It Worked

从我的理解而言,Handler像一个人的左右手,左手将一个个的鸡蛋放在篮子里(有序性),右手则从篮子里将鸡蛋一个个取出。左手和右手虽然都是你的,但是它们工作在不同的线程(同一个变量可以由不同的线程使用,这个可以理解吧,它们分别对应于消息的发送和消息的接收),而这个篮子(对应于MessageQueue)就充当了沟通两只手的一个媒介(将任务由子线程转移到主线程)

Relative Conception

MessageQueue

消息队列,内部存储结构是一个单链表

Looper

消息循环

  • MessageQueue只是一个存储单元,它不能去处理消息,而Looper则填补了这个功能
  • Looper会以无限循环的形式去查找是否有新消息,有的话就处理,无则等待
  • 线程默认是没有Looper的,如果要使用Handler,需要为该线程创建 Looper (UI线程就是ActivityThread,在创建的时候,就会初始化 Looper)

Looper的创建:

  • Looper.prepare() --> looper.loop() /启动消息循环
    prepareMainLooper VS getMainLooper/可在任何线程获取 (主线程Looper的特殊性)
    在子线程中创建完 Looper后,应该在所有消息处理完毕的时候,退出Looper,不然线程就会一直处于等待的状态,而退出Looper过后,线程会立即终止
  • loop #Looper
    loop方法是一个死循环(除非MessageQueue的next返回null),loop会调用
    MessageQueue的next方法(这是一个阻塞方法),要么读取到新的消息,要么等待,
    要么返回null( 当Looper的quit方法被调用,消息队列被标记为退出状态,next返回
    null)

ThreadLocal

1. 功能
ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定的线程中可以获取到存储的数据
2. 必要性
如果不使用 ThreadLocal,那么就需要提供一个全局的哈希表供Handler查找指定线程 的Looper,不是良好的封装
其它:
ThreadLocal还可以用于复杂逻辑下的对象传递,比如监听器的传递

理解 ThreadLocal 的实现方式有助于理解 Looper 的工作原理

Process

MessageQueue主要包含插入和读取两个操作,读取的操作伴随着删除(出队列),相关的方法是 enqueueMessage 和 next 方法

Handler的工作原理
Hanlder的工作主要是以下两点:

  • 消息的发送
    通过post 的一系列方法以及send的一系列方法来实现,post最终也是通过send
  • 消息的接收

那你可能会有疑问,发送完了就接收,那还发送个啥,直接处理不就行了么?肯定不行,因
为要排队,加入队列和取出队列的操作,涉及到 Looper 和 MessageQueue。Handler的主要任务就是将要处理的任务,以有序的方式排好队,交给目标线程,这样就很好地避免了因为资源的竞争而产生的一些不安全的操作,遵循的原则就是同一时刻只有一个任务被目标线程处理,待这个任务处理完毕,再接收下一个任务。

详解Send过程

public final boolean sendMessage( Message msg ){
	//这样设计挺好的sendMessageDelayed通用的接口,当delayed=0就相当sendMessage
	return sendMessageDelayed( msg,0 ); 
}

public final boolean sendMessageDelayed( Message msg, long delayMillis){
	sendMessageAtTime( msg, SystemClock.uptimeMillis()+delayMillis );
}
// uptimeMillis(系统的当前时间,从开机到现在不包括手机睡眠的时间)
//那么uptimeMillis+delayeMillis其实就是这个消息应该发送的时间点

//判断mQueue是否为空
public boolean sendMessageAtTime ( Message msg, long uptimeMillis {
	MessageQueue queue = mQueue;
	if( queue==null ){
		RuntimeException e = new RuntimeException( this +sendMessageAtTime()
				called with no mQueue”);
		Log.d(“Looper”,e.getMessage, e);
		return false;
	}	
	return enqueueMessage( queue,msg,uptimeMillis );
}
//mQueue不为空则发送消息
private boolean enqueueMessage( MessageQueue queue,Message msg, long 				uptimeMillis){
	msg.target = this;  //让msg携带Handler的引用
	if( mAsynchronous){
		msg.setAsynchronous(true);
	}
	return queue.enqueueMessage( msg,uptimeMillis );
}

Handler的发送消息的过程仅仅是以上,向消息队列中插入一条消息,一旦消息队列不为空,MessageQueue的next方法就会返回最前面的消息给Looper,Looper收到消息就开始处理了,最终消息由Looper交回Hanlder处理,即Handler的 dispatchMessage方法会被调用

public void dispatchMessage ( Message msg ){
		if ( msg.callback != null ){
				handleCallback ( msg );
		} else{
				if ( mCallback!=null ){  // mCallback 是一个Callback接口的实现
						if ( mCallback.handleMessage (msg) )
							return ;
				}
				handleMessage (msg) ;
		}
}

private static void handleCallback( Message msg ){
		msg.callback.run();
}

  • 其实就是分几种情况
  1. msg内部包裹了一个callback(Runnable对象),那直接callback.run就可以了
  2. 如果没有包裹,那就看mCallback是否被初始化,Handler创建的时候,是否传入了一个CallBack接口(需实现它的HandleMessage 方法)实例,有的话,那就直接调用
  3. 如果自身的 mCallback 变量没有在创建的时候被赋值,则调用重写的Handler的handleMessage方法
  • 2与3的处理有点类似于Thread的创建过程,既可以传入 Runnable对象,也可以重写Thread的run方法
Handler handler = new Handler ( new Callback(){
		@Override
		public boolean handleMessage(Message msg){
					//your code here
		}
}) //这个传入的 Callback 对象会赋值给 Hanlder内部的 mCallback
或者
Handler handler = new Handler(){
		@Override
		public void handleMessage( Message msg ){
				// your code here
		}
}

Handler的一个特殊的构造方法

Handler mHandler = new Handler(looper);
looper可以通过 Thread.getLooper()获取到,前提是目标线程初始化了 Looper,这个构造方法一般用于在线程外部构造与该线程关联的 Handler。可以与HanlderService这一章结合起来看

Handler In MainThread

主线程的消息循环

Android 的主线程就是 ActivityThread,主线程的入口方法为 main,在 main方法中系统会通过 Looper.prepareMainLooper() 来创建主线程的 Looper以及 MessageQueue,并通过Looper.loop() 来开启主线程的消息循环。

补充 # 需要进一步学习进程和线程相关知识才能理解
ActivityThread 的 handler是 ActivityThread.H,

  • ActivityThread.H内部定义了一组消息类型,主要包含了四大组件的启动和暂停等过程
  • ApplicationThread:
    ActivityThread通过 ApplicationThread 和 AMS 进行进程间通信,AMS以进程间通信
    的方式完成 ActivityThread的请求后回调ApplicationThread中的Binder方法,然后
    ApplicationThread会向H发送消息, H收到消息后会将 ApplicationThread中的逻辑切
    换到ActivityThread中去执行,即切换到主线程中去执行,这个过程就是主线程的消息
    循环模型

Ref:任玉刚《Android开发艺术探索》
技术有限,如果文中存在错误,烦请指出,不甚感激

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值