Android源码之Handler(一)

在Android系统中,Handler是一个很重要的概念.可以说,在Android系统中,Handler的身影无处不在。

Handler提供了若干个构造函数,我们就从Handler的构造函数来开始分析Handler系统的实现.Handler的构造函数的实现如下:

[//Handler的构造函数

publicHandler(){

this(null,false);

}

publicHandler(Callbackcallback){

this(callback,false);

}

publicHandler(Looperlooper){

this(looper,null,false);

}

publicHandler(Looperlooper,Callbackcallback){

this(looper,callback,false);

}

publicHandler(booleanasync){

this(null,async);

}

publicHandler(Callbackcallback,booleanasync){

if(FIND_POTENTIAL_LEAKS){

[//FIND_POTENTIAL_LEAKS

privatestaticfinalbooleanFIND_POTENTIAL_LEAKS=false;

FIND_POTENTIAL_LEAKS设置为true的时候,会检测内存泄漏可能性.

]//FIND_POTENTIAL_LEAKS

finalClass<?extendsHandler>klass=getClass();

if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&

(klass.getModifiers()&Modifier.STATIC)==0){

Log.w(TAG,"ThefollowingHandlerclassshouldbestaticorleaksmightoccur:"+

klass.getCanonicalName());

}

[//if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&(klass.getModifiers()&Modifier.STATIC)==0)

检测内存泄漏是通过Java的反射机制来实现的.

]//if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&(klass.getModifiers()&Modifier.STATIC)==0)

}

[//if(FIND_POTENTIAL_LEAKS)

这段代码是为了检测Handler可能的内存泄漏.当Handler被继承定义成匿名函数或者是某一类的内部类的时候,如果不把该Handler定义成static,则可能发生内存泄漏.为什么呢?

因为不是static的内部类会默认持有一个指向父类的指针,而发给这个Handler的Message又会持有这个Handler的指针.这样如果这个Message不销毁的话,则这个Handler是不会被垃圾回收的.

]//if(FIND_POTENTIAL_LEAKS)

mLooper=Looper.myLooper();

[//mLooper=Looper.myLooper()

得到的是当前线程的Looper.那么这个Looper是个什么呢?在这里我们先来看一下Looper的实现。

在Android系统中,Looper是按照如下方式使用的:

classLooperThreadextendsThread{

*publicHandlermHandler;

*

*publicvoidrun(){

*Looper.prepare();

*

*mHandler=newHandler(){

*publicvoidhandleMessage(Messagemsg){

*//processincomingmessageshere

*}

*};

*

*Looper.loop();

*}

*}

由上面的代码可以看出,使用Looper要先调用Looper.prepare函数,然后构造一个Handler对象,最后调用Looper.loop函数。经过上面的过程之后,就可以利用Handler机制来发送和处理消息了。

我们先来看一下prepare的实现:

publicstaticvoidprepare(){

prepare(true);

}

privatestaticvoidprepare(booleanquitAllowed){

if(sThreadLocal.get()!=null){

[//if(sThreadLocal.get()!=null)

这里首先会先判断之前是否已经为线程设置过Looper

sThreadLocal是Looper内部定义的一个static成员变量,定义如下:

staticfinalThreadLocal<Looper>sThreadLocal=newThreadLocal<Looper>();

ThreadLocal的构造函数定义如下:

[//ThreadLocal的构造函数

publicThreadLocal(){}

由此可见,ThreadLocal的构造函数是个空函数,什么也不做。

]//ThreadLocal的构造函数

注意,这里的成员变量sThreadLocal是static的。

我们接下来看一下ThreadLocal的get函数的实现:

publicTget(){

//Optimizedforthefastpath.

ThreadcurrentThread=Thread.currentThread();

[//ThreadcurrentThread=Thread.currentThread()

这里调用Thread的currentThread函数当得到当前线程。

]//ThreadcurrentThread=Thread.currentThread()

Valuesvalues=values(currentThread);

[//Valuesvalues=values(currentThread)

当得到了当前线程的Thread变量之后,会调用values函数。values函数的定义如下:

Valuesvalues(Threadcurrent){

returncurrent.localValues;

}

values函数会直接返回Thread变量的localValues变量,由此可知,其实TheadLocal机制其实是将值保存到每一个Thread变量中去的.

]//Valuesvalues=values(currentThread)

if(values!=null){

[//if(values!=null)

下面这段代码是在当前线程的localValues成员变量中取ThreadLocal保存的值。

]//if(values!=null)

Object[]table=values.table;

intindex=hash&values.mask;

[//intindex=hash&values.mask

这句代码实在计算索引值。mask的值就是HashTable的长度。那么这个hash变量的值是如何计算的呢?

我们看一下hash成员变量是如何初始化的?

privatefinalinthash=hashCounter.getAndAdd(0x61c88647*2);

privatestaticAtomicIntegerhashCounter=newAtomicInteger(0);

我们看到,hash成员变量是final的,并且是非static的。也就是说每一个ThreadLocal对象持有一个hash变量。更进一步,我们可以得到这样的结论:对于某一类的ThreadLocal变量(通俗的讲就是ThreadLocal的模版参数一样),其实维护的是一个hash变量值,也就是说会映射到同一个索引的地方去。

]//intindex=hash&values.mask

if(this.reference==table[index]){

return(T)table[index+1];

}

[//if(this.reference==table[index])

在Values的实现中,table会在index保存ThreadLocal对象,而在index+1的位置保存ThreadLocal的值。为什么要这么设计呢?

我们先来看一下reference的定义:

privatefinalReference<ThreadLocal<T>>reference=newWeakReference<ThreadLocal<T>>(this);

可以看到reference是个弱引用。所以这里要先比较一下reference和table[index].是为了防止内存回收。

]//if(this.reference==table[index])

}else{

values=initializeValues(currentThread);

[//values=initializeValues(currentThread)

ValuesinitializeValues(Threadcurrent){

returncurrent.localValues=newValues();

[//newValues()

Values类是ThreadLocal的一个内部类,其实它的作用就是一个HashTable.我们先来看一下Values的构造函数:

Values(){

initializeTable(INITIAL_SIZE);

[//initializeTable(INITIAL_SIZE)

privatevoidinitializeTable(intcapacity){

this.table=newObject[capacity*2];

this.mask=table.length-1;

this.clean=0;

this.maximumLoad=capacity*2/3;//2/3

}

initializeTable函数就是初始化Values的几个重要的成员变量。

INITIAL_SIZE是Values定义的常量。

privatestaticfinalintINITIAL_SIZE=16;

]//initializeTable(INITIAL_SIZE)

this.size=0;

this.tombstones=0;

}

]//newValues()

}

如果当前线程还没有设置过localValues,则会创建一个Values对象,并赋值给当前线程。

]//values=initializeValues(currentThread)

}

return(T)values.getAfterMiss(this);

[//values.getAfterMiss(this)

当第一个索引位置没有得到值的情况下或者第一次设置Values成员变量,则会调用getAfterMiss来尝试查找有冲突的情况下的值:

ObjectgetAfterMiss(ThreadLocal<?>key){

Object[]table=this.table;

intindex=key.hash&mask;

if(table[index]==null){

[//if(table[index]==null)

如果table的index索引的位置的值是null,则说明没有发生过冲突,也就没有必要在继续查找index之后的位置

]//if(table[index]==null)

Objectvalue=key.initialValue();

[//Objectvalue=key.initialValue();

这里会调用ThreadLocal的initialValue函数来初始化一个值

protectedTinitialValue(){

returnnull;

}

默认的initialValue函数的实现就是返回null

]//Objectvalue=key.initialValue();

if(this.table==table&&table[index]==null){

[//if(this.table==table&&table[index]==null)

这里为什么还要判断一下?是为了防止在initialValue函数中改变了table,如果发现没有改变,则设置

]//if(this.table==table&&table[index]==null)

table[index]=key.reference;

table[index+1]=value;

size++;

cleanUp();

[//cleanUp()

这里还会调用cleanUp函数来清空失效的

privatevoidcleanUp(){

if(rehash()){

[//if(rehash())

这里会先判断是否需要rehash。如果rehash了,则不必往下进行了.rehash函数的定义如下:

privatebooleanrehash(){

if(tombstones+size<maximumLoad){

returnfalse;

}

[//if(tombstones+size<maximumLoad)

tombstones+size表示目前装载的数目

]//if(tombstones+size<maximumLoad)

intcapacity=table.length>>1;

[//intcapacity=table.length>>1

因为在hashtable中,其实是用两个位置来表示一个真正的值的。因此容量就应该为table的长度的一半。

]//intcapacity=table.length>>1

intnewCapacity=capacity;

if(size>(capacity>>1)){

newCapacity=capacity*2;

}

[//if(size>(capacity>>1))

上面这段代码是判断是否需要扩充hashtable的容量。条件就是现在有效的值的个数已经超过了容量的一半。

]//if(size>(capacity>>1))

Object[]oldTable=this.table;

initializeTable(newCapacity);

this.tombstones=0;

[//this.tombstones=0;

这里是初始化了一个新的hashtable

]//this.tombstones=0;

if(size==0){

returntrue;

}

[//if(size==0)

如果当前没有有效的值,这直接返回

]//if(size==0)

for(inti=oldTable.length-2;i>=0;i-=2){

[//for(inti=oldTable.length-2;i>=0;i-=2)

在这个for循环里,将老的hashtable里的值拷贝到新的hashtable中去

]//for(inti=oldTable.length-2;i>=0;i-=2)

Objectk=oldTable[i];

if(k==null||k==TOMBSTONE){

continue;

}

[//if(k==null||k==TOMBSTONE)

如果发现是无效的则跳过

]//if(k==null||k==TOMBSTONE)

@SuppressWarnings("unchecked")

Reference<ThreadLocal<?>>reference=(Reference<ThreadLocal<?>>)k;

ThreadLocal<?>key=reference.get();

if(key!=null){

[//if(key!=null)

如果这个ThreadLocal对象没有被回收,还是有效的,则将这个值放到新的hashtable中去

]//if(key!=null)

add(key,oldTable[i+1]);

[//add(key,oldTable[i+1])

调用add函数来增加一个值.add函数的定义如下:

voidadd(ThreadLocal<?>key,Objectvalue){

for(intindex=key.hash&mask;;index=next(index)){

[//for(intindex=key.hash&mask;;index=next(index))

for循环查找一个可以插入的位置。初始的索引是用ThreadLocal的hash变量的值和Values的成员变量mask做与运算。由此可以看出,一类的ThreadLocal的值是放在一个索引位置上的。

next函数是计算下一个索引位置。next函数的定义如下:

privateintnext(intindex){

return(index+2)&mask;

}

正如我们之前分析的那样,在hashtable中其实是用两个位置来表示一个值的。

]//for(intindex=key.hash&mask;;index=next(index))

Objectk=table[index];

if(k==null){

table[index]=key.reference;

table[index+1]=value;

return;

}

[//if(k==null)

发现一个空位置,则将值写入到这里。

]//if(k==null)

}

}

]//add(key,oldTable[i+1])

}else{

[//else

这里是表示垃圾回收的情况

]//else

size--;

}

}

returntrue;

}

]//if(rehash())

return;

}

if(size==0){

return;

}

[//if(size==0)

size为0表示有效的值为空,则不需要往下进行了

]//if(size==0)

intindex=clean;

[//intindex=clean

在Values类的设计中,有一个成员变量clean,记录上次清理结束的位置。为什么要记录这个位置呢?效率会高多少呢?

]//intindex=clean

Object[]table=this.table;

for(intcounter=table.length;counter>0;counter>>=1,index=next(index)){

Objectk=table[index];

if(k==TOMBSTONE||k==null){

continue;//ontonextentry

}

@SuppressWarnings("unchecked")

Reference<ThreadLocal<?>>reference=(Reference<ThreadLocal<?>>)k;

if(reference.get()==null){

table[index]=TOMBSTONE;

table[index+1]=null;

tombstones++;

size--;

}

[//if(reference.get()==null)

这里发现被垃圾回收的,则将这个位置标记为TOMBSTONE.

]//if(reference.get()==null)

}

clean=index;

[//clean=index

记录下次清理的位置

]//clean=index

}

]//cleanUp()

returnvalue;

}

//ThetablechangedduringinitialValue().

put(key,value);

[//put(key,value)

如果发现在调用initialValue函数过程中,hashtable已经发生了改变,则直接将这个值插入到hashtable中.

put函数的实现如下:

voidput(ThreadLocal<?>key,Objectvalue){

cleanUp();

[//cleanUp()

put函数首先调用cleanUp函数

]//cleanUp()

intfirstTombstone=-1;

[//intfirstTombstone=-1

这里用一个变量firstTombstone记录发现的第一个TOMBSTONE的位置,为什么要记录这个位置呢?因为TOMBSTONE表示被垃圾回收之后的对该位置的表示。

]//intfirstTombstone=-1

for(intindex=key.hash&mask;;index=next(index)){

Objectk=table[index];

if(k==key.reference){

table[index+1]=value;

return;

}

[//if(k==key.reference)

这里发现了同样一个ThreadLocal对象,则直接替换值

]//if(k==key.reference)

if(k==null){

if(firstTombstone==-1){

//Fillinnullslot.

table[index]=key.reference;

table[index+1]=value;

size++;

return;

}

//Gobackandreplacefirsttombstone.

table[firstTombstone]=key.reference;

table[firstTombstone+1]=value;

tombstones--;

size++;

return;

}

[//if(k==null)

如果当前索引值位置的值为null,则说明发现了一个没有用过的位置,则不必继续搜索了。这里还会将值保存到合适的索引值的位置上去。

]//if(k==null)

//Rememberfirsttombstone.

if(firstTombstone==-1&&k==TOMBSTONE){

firstTombstone=index;

}

}

}

]//put(key,value)

returnvalue;

}

intfirstTombstone=-1;

for(index=next(index);;index=next(index)){

Objectreference=table[index];

if(reference==key.reference){

returntable[index+1];

}

if(reference==null){

Objectvalue=key.initialValue();

if(this.table==table){

if(firstTombstone>-1&&table[firstTombstone]==TOMBSTONE){

table[firstTombstone]=key.reference;

table[firstTombstone+1]=value;

tombstones--;

size++;

returnvalue;

}

if(table[index]==null){

table[index]=key.reference;

table[index+1]=value;

size++;

cleanUp();

returnvalue;

}

}

put(key,value);

returnvalue;

}

if(firstTombstone==-1&&reference==TOMBSTONE){

firstTombstone=index;

}

}

[//for(index=next(index);;index=next(index))

上面这段代码是不是看着很眼熟,和put函数中的实现是相似的。

]//for(index=next(index);;index=next(index))

}

]//values.getAfterMiss(this)

}

]//if(sThreadLocal.get()!=null)

thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");

}

sThreadLocal.set(newLooper(quitAllowed));

[//sThreadLocal.set(newLooper(quitAllowed))

如果sThreadLocal.get函数为null,则说明还没有为当前线程设置过Looper对象,则这里就调用ThreadLocal的set函数来为当前线程new一个Looper对象。

我们先来看一下Looper的构造函数:

privateLooper(booleanquitAllowed){

mQueue=newMessageQueue(quitAllowed);

[//mQueue=newMessageQueue(quitAllowed)

在Looper类中,有一个MessageQueue的成员变量mQueue,定义如下:

finalMessageQueuemQueue;

也就是说每一个Looper内部维护了一个MessageQueue。

我们看一下MessageQueue的构造函数:

MessageQueue(booleanquitAllowed){

mQuitAllowed=quitAllowed;

mPtr=nativeInit();

[//mPtr=nativeInit()

这里会调用nativeInit()函数。从名字可以猜测这是个native函数。

privatenativestaticlongnativeInit();

果不其然,确实是个native函数。

调用nativeInit函数其实是调用的android_os_MessageQueue.cpp(为与/home/yaojian/AndroidSource/frameworks/base/core/jni文件夹下)的android_os_MessageQueue_nativeInit函数:

staticjlongandroid_os_MessageQueue_nativeInit(JNIEnv*env,jclassclazz){

NativeMessageQueue*nativeMessageQueue=newNativeMessageQueue();

[//NativeMessageQueue*nativeMessageQueue=newNativeMessageQueue()

这里会创建一个C++层的NativeMessageQueue的对象。

我们先来看一下NativeMessageQueue的类结构:

classNativeMessageQueue:publicMessageQueue

classMessageQueue:publicRefBase

MessageQueue继承自RefBase类,由此可知可以用智能指针来管理MessageQueue类。

我们再来看一下NativeMessageQueue类的构造函数:

MessageQueue::MessageQueue(){

}

NativeMessageQueue::NativeMessageQueue():mInCallback(false),mExceptionObj(NULL){

mLooper=Looper::getForThread();

[//mLooper=Looper::getForThread()

在NativeMessageQueue类中也有一个Looper类型的成员变量mLooper,mLooper的定义如下:

sp<Looper>mLooper;

这里mLooper的初始化是通过Looper的getForThread函数来实现的:

sp<Looper>Looper::getForThread(){

intresult=pthread_once(&gTLSOnce,initTLSKey);

[//intresult=pthread_once(&gTLSOnce,initTLSKey)

这里这个pthread_once函数是干什么的呢?我也不知道,百度一下查出下面的解释:

intpthread_once(pthread_once_t*once_control,void(*init_routine)(void))

本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。

也就是说pthread_once保证了initTLSKey函数之调用一次,gTLSOnce和initTLSKey的定义如下:

staticpthread_once_tgTLSOnce=PTHREAD_ONCE_INIT;

initTLSKey函数的实现如下:

voidLooper::initTLSKey(){

intresult=pthread_key_create(&gTLSKey,threadDestructor);

[//intresult=pthread_key_create(&gTLSKey,threadDestructor)

在initTLSKey函数中,会调用pthread_key_create函数。那么这个pthread_key_create函数有什么作用么?我也不知道啊?还是百度一下吧:

intpthread_key_create(pthread_key_t*key,void(*destructor)(void*));

函数pthread_key_create()用来创建线程私有数据。该函数从TSD池中分配一项,将其地址值赋给key供以后访问使用。第2个参数是一个销毁函数,它是可选的,可以为NULL,为NULL时,则系统调用默认的销毁函数进行相关的数据注销。如果不为空,则在线程退出时(调用pthread_exit()函数)时将以key锁关联的数据作为参数调用它,以释放分配的缓冲区,或是关闭文件流等。

gTLSKey和threadDestructor的定义如下:

staticpthread_key_tgTLSKey=0;

voidLooper::threadDestructor(void*st){

Looper*constself=static_cast<Looper*>(st);

if(self!=NULL){

self->decStrong((void*)threadDestructor);

}

}

]//intresult=pthread_key_create(&gTLSKey,threadDestructor)

LOG_ALWAYS_FATAL_IF(result!=0,"CouldnotallocateTLSkey.");

}

]//intresult=pthread_once(&gTLSOnce,initTLSKey)

LOG_ALWAYS_FATAL_IF(result!=0,"pthread_oncefailed");

return(Looper*)pthread_getspecific(gTLSKey);

[//return(Looper*)pthread_getspecific(gTLSKey)

在getForThread函数的最后会调用pthread_getspecific函数。那pthread_getspecific函数是干什么呢?又一次不知道,这次我决定不求助百度了,求助Google:

void*pthread_getspecific(pthread_key_tkey);

函数pthread_getspecific()将与key相关联的数据读出来。返回的数据类型都是void*,因此可以指向任何类型的数据。

]//return(Looper*)pthread_getspecific(gTLSKey)

}

[//sp<Looper>Looper::getForThread()

通过分析getForThread函数的实现,我们发现其实这个ThreadLocal的实现是很相似的。

那为什么还在C++层在实现一套呢?现在还不知道啊.

]//sp<Looper>Looper::getForThread()

]//mLooper=Looper::getForThread()

if(mLooper==NULL){

[//if(mLooper==NULL)

这里如果当前线程的Looper返回的空,则要为当前线程设置一个新的Looper对象

]//if(mLooper==NULL)

mLooper=newLooper(false);

[//mLooper=newLooper(false)

这里会先new一个C++层的Looper对象。我们看一下Looper的构造函数:

Looper::Looper(boolallowNonCallbacks):

mAllowNonCallbacks(allowNonCallbacks),mSendingMessage(false),

mResponseIndex(0),mNextMessageUptime(LLONG_MAX){

intwakeFds[2];

intresult=pipe(wakeFds);

LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotcreatewakepipe.errno=%d",errno);

mWakeReadPipeFd=wakeFds[0];

mWakeWritePipeFd=wakeFds[1];

result=fcntl(mWakeReadPipeFd,F_SETFL,O_NONBLOCK);

LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotmakewakereadpipenon-blocking.errno=%d",

errno);

result=fcntl(mWakeWritePipeFd,F_SETFL,O_NONBLOCK);

LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotmakewakewritepipenon-blocking.errno=%d",

errno);

mIdling=false;

//Allocatetheepollinstanceandregisterthewakepipe.

mEpollFd=epoll_create(EPOLL_SIZE_HINT);

LOG_ALWAYS_FATAL_IF(mEpollFd<0,"Couldnotcreateepollinstance.errno=%d",errno);

structepoll_eventeventItem;

memset(&eventItem,0,sizeof(epoll_event));//zerooutunusedmembersofdatafieldunion

eventItem.events=EPOLLIN;

eventItem.data.fd=mWakeReadPipeFd;

result=epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeReadPipeFd,&eventItem);

LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotaddwakereadpipetoepollinstance.errno=%d",

errno);

}

在Looper的构造函数中,会创建两个管道:mWakeReadPipeFd和mWakeWritePipeFd。并且利用epoll机制来设置监听mWakeReadPipeFd。

]//mLooper=newLooper(false)

Looper::setForThread(mLooper);

[//Looper::setForThread(mLooper)

当创建完C++层的Looper对象之后,就可以调用setForThread函数来将该对象设置到当前线程中去。

voidLooper::setForThread(constsp<Looper>&looper){

sp<Looper>old=getForThread();//alsohasside-effectofinitializingTLS

if(looper!=NULL){

looper->incStrong((void*)threadDestructor);

}

pthread_setspecific(gTLSKey,looper.get());

if(old!=NULL){

old->decStrong((void*)threadDestructor);

}

}

]//Looper::setForThread(mLooper)

}

}

]//NativeMessageQueue*nativeMessageQueue=newNativeMessageQueue()

if(!nativeMessageQueue){

jniThrowRuntimeException(env,"Unabletoallocatenativequeue");

return0;

}

nativeMessageQueue->incStrong(env);

returnreinterpret_cast<jlong>(nativeMessageQueue);

}

当创建完C++层的NativeMessageQueue之后,就得到这个C++层的NativeMessageQueue的句柄,并赋值给成员变量mPtr.mPtr的定义如下:

privatelongmPtr;//usedbynativecode

由此得出结论,每一个Java层的MessageQueue对象在C++曾都有一个NativeMessageQueue对象。

]//mPtr=nativeInit()

}

]//mQueue=newMessageQueue(quitAllowed)

mThread=Thread.currentThread();

}

[//privateLooper(booleanquitAllowed)

首先我们注意到Looper的构造函数是private的。

]//privateLooper(booleanquitAllowed)

当构造完Looper对象之后,就会调用ThreadLocal的set函数来将该Looper对象保存到当前线程的ThreadLocal中去。

我们来看一下ThreadLocal类的set函数的实现:

publicvoidset(Tvalue){

ThreadcurrentThread=Thread.currentThread();

Valuesvalues=values(currentThread);

if(values==null){

values=initializeValues(currentThread);

}

values.put(this,value);

}

[//publicvoidset(Tvalue)

set函数的实现还是比较清晰的,里面调用的函数我们之前都分析过。

]//publicvoidset(Tvalue)

]//sThreadLocal.set(newLooper(quitAllowed))

}

相关推荐