- 浏览: 23768 次
- 性别:
- 来自: 北京
最新评论
在Android系统中,Handler是一个很重要的概念.可以说,在Android系统中,Handler的身影无处不在。
Handler提供了若干个构造函数,我们就从Handler的构造函数来开始分析Handler系统的实现. Handler的构造函数的实现如下:
[// Handler的构造函数
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
[// FIND_POTENTIAL_LEAKS
private static final boolean FIND_POTENTIAL_LEAKS = false;
FIND_POTENTIAL_LEAKS设置为true的时候, 会检测内存泄漏可能性.
]// 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());
}
[// 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是按照如下方式使用的:
class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }
由上面的代码可以看出, 使用Looper要先调用Looper.prepare函数, 然后构造一个Handler对象,最后调用Looper.loop函数。经过上面的过程之后,就可以利用Handler机制来发送和处理消息了。
我们先来看一下prepare的实现:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
[// if (sThreadLocal.get() != null)
这里首先会先判断之前是否已经为线程设置过Looper
sThreadLocal是Looper内部定义的一个static成员变量,定义如下:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal的构造函数定义如下:
[// ThreadLocal的构造函数
public ThreadLocal() {}
由此可见,ThreadLocal的构造函数是个空函数,什么也不做。
]// ThreadLocal的构造函数
注意,这里的成员变量sThreadLocal是static的。
我们接下来看一下ThreadLocal的get函数的实现:
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
[// Thread currentThread = Thread.currentThread()
这里调用Thread的currentThread函数当得到当前线程。
]// Thread currentThread = Thread.currentThread()
Values values = values(currentThread);
[// Values values = values(currentThread)
当得到了当前线程的Thread变量之后, 会调用values函数。values函数的定义如下:
Values values(Thread current) {
return current.localValues;
}
values函数会直接返回Thread变量的localValues变量,由此可知,其实TheadLocal机制其实是将值保存到每一个Thread变量中去的.
]// Values values = values(currentThread)
if (values != null) {
[// if (values != null)
下面这段代码是在当前线程的localValues成员变量中取ThreadLocal保存的值。
]// if (values != null)
Object[] table = values.table;
int index = hash & values.mask;
[// int index = hash & values.mask
这句代码实在计算索引值。mask的值就是Hash Table的长度。那么这个hash变量的值是如何计算的呢?
我们看一下hash成员变量是如何初始化的?
private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
private static AtomicInteger hashCounter = new AtomicInteger(0);
我们看到, hash成员变量是final的,并且是非static的。也就是说每一个ThreadLocal对象持有一个hash变量。更进一步,我们可以得到这样的结论:对于某一类的ThreadLocal变量(通俗的讲就是ThreadLocal的模版参数一样),其实维护的是一个hash变量值,也就是说会映射到同一个索引的地方去。
]// int index = 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的定义:
private final Reference<ThreadLocal<T>> reference = new WeakReference<ThreadLocal<T>>(this);
可以看到reference是个弱引用。所以这里要先比较一下reference和table[index]. 是为了防止内存回收。
]// if (this.reference == table[index])
} else {
values = initializeValues(currentThread);
[// values = initializeValues(currentThread)
Values initializeValues(Thread current) {
return current.localValues = new Values();
[// new Values()
Values类是ThreadLocal的一个内部类, 其实它的作用就是一个Hash Table. 我们先来看一下Values的构造函数:
Values() {
initializeTable(INITIAL_SIZE);
[// initializeTable(INITIAL_SIZE)
private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
}
initializeTable函数就是初始化Values的几个重要的成员变量。
INITIAL_SIZE是Values定义的常量。
private static final int INITIAL_SIZE = 16;
]// initializeTable(INITIAL_SIZE)
this.size = 0;
this.tombstones = 0;
}
]// new Values()
}
如果当前线程还没有设置过localValues, 则会创建一个Values对象,并赋值给当前线程。
]// values = initializeValues(currentThread)
}
return (T) values.getAfterMiss(this);
[// values.getAfterMiss(this)
当第一个索引位置没有得到值的情况下或者第一次设置Values成员变量,则会调用getAfterMiss来尝试查找有冲突的情况下的值:
Object getAfterMiss(ThreadLocal<?> key) {
Object[] table = this.table;
int index = key.hash & mask;
if (table[index] == null) {
[// if (table[index] == null)
如果table的index索引的位置的值是null, 则说明没有发生过冲突,也就没有必要在继续查找index之后的位置
]// if (table[index] == null)
Object value = key.initialValue();
[// Object value = key.initialValue();
这里会调用ThreadLocal的initialValue函数来初始化一个值
protected T initialValue() {
return null;
}
默认的initialValue函数的实现就是返回null
]// Object value = 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函数来清空失效的
private void cleanUp() {
if (rehash()) {
[// if (rehash())
这里会先判断是否需要rehash。如果rehash了,则不必往下进行了.rehash函数的定义如下:
private boolean rehash() {
if (tombstones + size < maximumLoad) {
return false;
}
[// if (tombstones + size < maximumLoad)
tombstones + size表示目前装载的数目
]// if (tombstones + size < maximumLoad)
int capacity = table.length >> 1;
[// int capacity = table.length >> 1
因为在hash table中, 其实是用两个位置来表示一个真正的值的。因此容量就应该为table的长度的一半。
]// int capacity = table.length >> 1
int newCapacity = capacity;
if (size > (capacity >> 1)) {
newCapacity = capacity * 2;
}
[// if (size > (capacity >> 1))
上面这段代码是判断是否需要扩充hash table的容量。条件就是现在有效的值的个数已经超过了容量的一半。
]// if (size > (capacity >> 1))
Object[] oldTable = this.table;
initializeTable(newCapacity);
this.tombstones = 0;
[// this.tombstones = 0;
这里是初始化了一个新的hash table
]// this.tombstones = 0;
if (size == 0) {
return true;
}
[// if (size == 0)
如果当前没有有效的值,这直接返回
]// if (size == 0)
for (int i = oldTable.length - 2; i >= 0; i -= 2) {
[// for (int i = oldTable.length - 2; i >= 0; i -= 2)
在这个for循环里,将老的hash table里的值拷贝到新的hash table中去
]// for (int i = oldTable.length - 2; i >= 0; i -= 2)
Object k = 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对象没有被回收,还是有效的,则将这个值放到新的hash table中去
]// if (key != null)
add(key, oldTable[i + 1]);
[// add(key, oldTable[i + 1])
调用add函数来增加一个值. add函数的定义如下:
void add(ThreadLocal<?> key, Object value) {
for (int index = key.hash & mask;; index = next(index)) {
[// for (int index = key.hash & mask;; index = next(index))
for循环查找一个可以插入的位置。初始的索引是用ThreadLocal的hash变量的值和Values的成员变量mask做与运算。由此可以看出,一类的ThreadLocal的值是放在一个索引位置上的。
next函数是计算下一个索引位置。next函数的定义如下:
private int next(int index) {
return (index + 2) & mask;
}
正如我们之前分析的那样,在hash table中其实是用两个位置来表示一个值的。
]// for (int index = key.hash & mask;; index = next(index))
Object k = 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--;
}
}
return true;
}
]// if (rehash())
return;
}
if (size == 0) {
return;
}
[// if (size == 0)
size为0表示有效的值为空,则不需要往下进行了
]// if (size == 0)
int index = clean;
[// int index = clean
在Values类的设计中,有一个成员变量clean, 记录上次清理结束的位置。为什么要记录这个位置呢?效率会高多少呢?
]// int index = clean
Object[] table = this.table;
for (int counter = table.length; counter > 0; counter >>= 1, index = next(index)) {
Object k = table[index];
if (k == TOMBSTONE || k == null) {
continue; // on to next entry
}
@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()
return value;
}
// The table changed during initialValue().
put(key, value);
[// put(key, value)
如果发现在调用initialValue函数过程中, hash table已经发生了改变,则直接将这个值插入到hash table中.
put函数的实现如下:
void put(ThreadLocal<?> key, Object value) {
cleanUp();
[// cleanUp()
put函数首先调用cleanUp函数
]// cleanUp()
int firstTombstone = -1;
[// int firstTombstone = -1
这里用一个变量firstTombstone记录发现的第一个TOMBSTONE的位置,为什么要记录这个位置呢?因为TOMBSTONE表示被垃圾回收之后的对该位置的表示。
]// int firstTombstone = -1
for (int index = key.hash & mask;; index = next(index)) {
Object k = 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) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
[// if (k == null)
如果当前索引值位置的值为null,则说明发现了一个没有用过的位置,则不必继续搜索了。这里还会将值保存到合适的索引值的位置上去。
]// if (k == null)
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
]// put(key, value)
return value;
}
int firstTombstone = -1;
for (index = next(index);; index = next(index)) {
Object reference = table[index];
if (reference == key.reference) {
return table[index + 1];
}
if (reference == null) {
Object value = key.initialValue();
if (this.table == table) {
if (firstTombstone > -1 && table[firstTombstone] == TOMBSTONE) {
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return value;
}
if (table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++;
cleanUp();
return value;
}
}
put(key, value);
return value;
}
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)
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
[// sThreadLocal.set(new Looper(quitAllowed))
如果sThreadLocal.get函数为null, 则说明还没有为当前线程设置过Looper对象,则这里就调用ThreadLocal的set函数来为当前线程new一个Looper对象。
我们先来看一下Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
[// mQueue = new MessageQueue(quitAllowed)
在Looper类中,有一个MessageQueue的成员变量mQueue,定义如下:
final MessageQueue mQueue;
也就是说每一个Looper内部维护了一个MessageQueue。
我们看一下MessageQueue的构造函数:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
[// mPtr = nativeInit()
这里会调用nativeInit()函数。从名字可以猜测这是个native函数。
private native static long nativeInit();
果不其然,确实是个native函数。
调用nativeInit函数其实是调用的android_os_MessageQueue.cpp(为与/home/yaojian/AndroidSource/frameworks/base/core/jni文件夹下)的android_os_MessageQueue_nativeInit函数:
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
[// NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue()
这里会创建一个C++层的NativeMessageQueue的对象。
我们先来看一下NativeMessageQueue的类结构:
class NativeMessageQueue : public MessageQueue
class MessageQueue : public RefBase
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() {
int result = pthread_once(&gTLSOnce, initTLSKey);
[// int result = pthread_once(&gTLSOnce, initTLSKey)
这里这个pthread_once函数是干什么的呢?我也不知道,百度一下查出下面的解释:
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。
也就是说pthread_once保证了initTLSKey函数之调用一次,gTLSOnce和initTLSKey的定义如下:
static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
initTLSKey函数的实现如下:
void Looper::initTLSKey() {
int result = pthread_key_create(&gTLSKey, threadDestructor);
[// int result = pthread_key_create(&gTLSKey, threadDestructor)
在initTLSKey函数中,会调用pthread_key_create函数。那么这个pthread_key_create函数有什么作用么?我也不知道啊?还是百度一下吧:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
函数 pthread_key_create() 用来创建线程私有数据。该函数从 TSD 池中分配一项,将其地址值赋给 key 供以后访问使用。第 2 个参数是一个销毁函数,它是可选的,可以为 NULL,为 NULL 时,则系统调用默认的销毁函数进行相关的数据注销。如果不为空,则在线程退出时(调用 pthread_exit() 函数)时将以 key 锁关联的数据作为参数调用它,以释放分配的缓冲区,或是关闭文件流等。
gTLSKey和threadDestructor的定义如下:
static pthread_key_t gTLSKey = 0;
void Looper::threadDestructor(void *st) {
Looper* const self = static_cast<Looper*>(st);
if (self != NULL) {
self->decStrong((void*)threadDestructor);
}
}
]// int result = pthread_key_create(&gTLSKey, threadDestructor)
LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
}
]// int result = pthread_once(&gTLSOnce, initTLSKey)
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
return (Looper*)pthread_getspecific(gTLSKey);
[// return (Looper*)pthread_getspecific(gTLSKey)
在getForThread函数的最后会调用pthread_getspecific函数。那pthread_getspecific函数是干什么呢?又一次不知道,这次我决定不求助百度了,求助Google:
void *pthread_getspecific(pthread_key_t key);
函数 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 = new Looper(false);
[// mLooper = new Looper(false)
这里会先new一个C++层的Looper对象。我们看一下Looper的构造函数:
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
mIdling = false;
// Allocate the epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
在Looper的构造函数中,会创建两个管道:mWakeReadPipeFd和mWakeWritePipeFd。并且利用epoll机制来设置监听mWakeReadPipeFd。
]// mLooper = new Looper(false)
Looper::setForThread(mLooper);
[// Looper::setForThread(mLooper)
当创建完C++层的Looper对象之后,就可以调用setForThread函数来将该对象设置到当前线程中去。
void Looper::setForThread(const sp<Looper>& looper) {
sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
if (looper != NULL) {
looper->incStrong((void*)threadDestructor);
}
pthread_setspecific(gTLSKey, looper.get());
if (old != NULL) {
old->decStrong((void*)threadDestructor);
}
}
]// Looper::setForThread(mLooper)
}
}
]// NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue()
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
当创建完C++层的NativeMessageQueue之后,就得到这个C++层的NativeMessageQueue的句柄,并赋值给成员变量mPtr. mPtr的定义如下:
private long mPtr; // used by native code
由此得出结论,每一个Java层的MessageQueue对象在C++曾都有一个NativeMessageQueue对象。
]// mPtr = nativeInit()
}
]// mQueue = new MessageQueue(quitAllowed)
mThread = Thread.currentThread();
}
[// private Looper(boolean quitAllowed)
首先我们注意到Looper的构造函数是private的。
]// private Looper(boolean quitAllowed)
当构造完Looper对象之后,就会调用ThreadLocal的set函数来将该Looper对象保存到当前线程的ThreadLocal中去。
我们来看一下ThreadLocal类的set函数的实现:
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
[// public void set(T value)
set函数的实现还是比较清晰的,里面调用的函数我们之前都分析过。
]// public void set(T value)
]// sThreadLocal.set(new Looper(quitAllowed))
}
Handler提供了若干个构造函数,我们就从Handler的构造函数来开始分析Handler系统的实现. Handler的构造函数的实现如下:
[// Handler的构造函数
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
[// FIND_POTENTIAL_LEAKS
private static final boolean FIND_POTENTIAL_LEAKS = false;
FIND_POTENTIAL_LEAKS设置为true的时候, 会检测内存泄漏可能性.
]// 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());
}
[// 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是按照如下方式使用的:
class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }
由上面的代码可以看出, 使用Looper要先调用Looper.prepare函数, 然后构造一个Handler对象,最后调用Looper.loop函数。经过上面的过程之后,就可以利用Handler机制来发送和处理消息了。
我们先来看一下prepare的实现:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
[// if (sThreadLocal.get() != null)
这里首先会先判断之前是否已经为线程设置过Looper
sThreadLocal是Looper内部定义的一个static成员变量,定义如下:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal的构造函数定义如下:
[// ThreadLocal的构造函数
public ThreadLocal() {}
由此可见,ThreadLocal的构造函数是个空函数,什么也不做。
]// ThreadLocal的构造函数
注意,这里的成员变量sThreadLocal是static的。
我们接下来看一下ThreadLocal的get函数的实现:
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
[// Thread currentThread = Thread.currentThread()
这里调用Thread的currentThread函数当得到当前线程。
]// Thread currentThread = Thread.currentThread()
Values values = values(currentThread);
[// Values values = values(currentThread)
当得到了当前线程的Thread变量之后, 会调用values函数。values函数的定义如下:
Values values(Thread current) {
return current.localValues;
}
values函数会直接返回Thread变量的localValues变量,由此可知,其实TheadLocal机制其实是将值保存到每一个Thread变量中去的.
]// Values values = values(currentThread)
if (values != null) {
[// if (values != null)
下面这段代码是在当前线程的localValues成员变量中取ThreadLocal保存的值。
]// if (values != null)
Object[] table = values.table;
int index = hash & values.mask;
[// int index = hash & values.mask
这句代码实在计算索引值。mask的值就是Hash Table的长度。那么这个hash变量的值是如何计算的呢?
我们看一下hash成员变量是如何初始化的?
private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
private static AtomicInteger hashCounter = new AtomicInteger(0);
我们看到, hash成员变量是final的,并且是非static的。也就是说每一个ThreadLocal对象持有一个hash变量。更进一步,我们可以得到这样的结论:对于某一类的ThreadLocal变量(通俗的讲就是ThreadLocal的模版参数一样),其实维护的是一个hash变量值,也就是说会映射到同一个索引的地方去。
]// int index = 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的定义:
private final Reference<ThreadLocal<T>> reference = new WeakReference<ThreadLocal<T>>(this);
可以看到reference是个弱引用。所以这里要先比较一下reference和table[index]. 是为了防止内存回收。
]// if (this.reference == table[index])
} else {
values = initializeValues(currentThread);
[// values = initializeValues(currentThread)
Values initializeValues(Thread current) {
return current.localValues = new Values();
[// new Values()
Values类是ThreadLocal的一个内部类, 其实它的作用就是一个Hash Table. 我们先来看一下Values的构造函数:
Values() {
initializeTable(INITIAL_SIZE);
[// initializeTable(INITIAL_SIZE)
private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
}
initializeTable函数就是初始化Values的几个重要的成员变量。
INITIAL_SIZE是Values定义的常量。
private static final int INITIAL_SIZE = 16;
]// initializeTable(INITIAL_SIZE)
this.size = 0;
this.tombstones = 0;
}
]// new Values()
}
如果当前线程还没有设置过localValues, 则会创建一个Values对象,并赋值给当前线程。
]// values = initializeValues(currentThread)
}
return (T) values.getAfterMiss(this);
[// values.getAfterMiss(this)
当第一个索引位置没有得到值的情况下或者第一次设置Values成员变量,则会调用getAfterMiss来尝试查找有冲突的情况下的值:
Object getAfterMiss(ThreadLocal<?> key) {
Object[] table = this.table;
int index = key.hash & mask;
if (table[index] == null) {
[// if (table[index] == null)
如果table的index索引的位置的值是null, 则说明没有发生过冲突,也就没有必要在继续查找index之后的位置
]// if (table[index] == null)
Object value = key.initialValue();
[// Object value = key.initialValue();
这里会调用ThreadLocal的initialValue函数来初始化一个值
protected T initialValue() {
return null;
}
默认的initialValue函数的实现就是返回null
]// Object value = 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函数来清空失效的
private void cleanUp() {
if (rehash()) {
[// if (rehash())
这里会先判断是否需要rehash。如果rehash了,则不必往下进行了.rehash函数的定义如下:
private boolean rehash() {
if (tombstones + size < maximumLoad) {
return false;
}
[// if (tombstones + size < maximumLoad)
tombstones + size表示目前装载的数目
]// if (tombstones + size < maximumLoad)
int capacity = table.length >> 1;
[// int capacity = table.length >> 1
因为在hash table中, 其实是用两个位置来表示一个真正的值的。因此容量就应该为table的长度的一半。
]// int capacity = table.length >> 1
int newCapacity = capacity;
if (size > (capacity >> 1)) {
newCapacity = capacity * 2;
}
[// if (size > (capacity >> 1))
上面这段代码是判断是否需要扩充hash table的容量。条件就是现在有效的值的个数已经超过了容量的一半。
]// if (size > (capacity >> 1))
Object[] oldTable = this.table;
initializeTable(newCapacity);
this.tombstones = 0;
[// this.tombstones = 0;
这里是初始化了一个新的hash table
]// this.tombstones = 0;
if (size == 0) {
return true;
}
[// if (size == 0)
如果当前没有有效的值,这直接返回
]// if (size == 0)
for (int i = oldTable.length - 2; i >= 0; i -= 2) {
[// for (int i = oldTable.length - 2; i >= 0; i -= 2)
在这个for循环里,将老的hash table里的值拷贝到新的hash table中去
]// for (int i = oldTable.length - 2; i >= 0; i -= 2)
Object k = 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对象没有被回收,还是有效的,则将这个值放到新的hash table中去
]// if (key != null)
add(key, oldTable[i + 1]);
[// add(key, oldTable[i + 1])
调用add函数来增加一个值. add函数的定义如下:
void add(ThreadLocal<?> key, Object value) {
for (int index = key.hash & mask;; index = next(index)) {
[// for (int index = key.hash & mask;; index = next(index))
for循环查找一个可以插入的位置。初始的索引是用ThreadLocal的hash变量的值和Values的成员变量mask做与运算。由此可以看出,一类的ThreadLocal的值是放在一个索引位置上的。
next函数是计算下一个索引位置。next函数的定义如下:
private int next(int index) {
return (index + 2) & mask;
}
正如我们之前分析的那样,在hash table中其实是用两个位置来表示一个值的。
]// for (int index = key.hash & mask;; index = next(index))
Object k = 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--;
}
}
return true;
}
]// if (rehash())
return;
}
if (size == 0) {
return;
}
[// if (size == 0)
size为0表示有效的值为空,则不需要往下进行了
]// if (size == 0)
int index = clean;
[// int index = clean
在Values类的设计中,有一个成员变量clean, 记录上次清理结束的位置。为什么要记录这个位置呢?效率会高多少呢?
]// int index = clean
Object[] table = this.table;
for (int counter = table.length; counter > 0; counter >>= 1, index = next(index)) {
Object k = table[index];
if (k == TOMBSTONE || k == null) {
continue; // on to next entry
}
@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()
return value;
}
// The table changed during initialValue().
put(key, value);
[// put(key, value)
如果发现在调用initialValue函数过程中, hash table已经发生了改变,则直接将这个值插入到hash table中.
put函数的实现如下:
void put(ThreadLocal<?> key, Object value) {
cleanUp();
[// cleanUp()
put函数首先调用cleanUp函数
]// cleanUp()
int firstTombstone = -1;
[// int firstTombstone = -1
这里用一个变量firstTombstone记录发现的第一个TOMBSTONE的位置,为什么要记录这个位置呢?因为TOMBSTONE表示被垃圾回收之后的对该位置的表示。
]// int firstTombstone = -1
for (int index = key.hash & mask;; index = next(index)) {
Object k = 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) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
[// if (k == null)
如果当前索引值位置的值为null,则说明发现了一个没有用过的位置,则不必继续搜索了。这里还会将值保存到合适的索引值的位置上去。
]// if (k == null)
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
]// put(key, value)
return value;
}
int firstTombstone = -1;
for (index = next(index);; index = next(index)) {
Object reference = table[index];
if (reference == key.reference) {
return table[index + 1];
}
if (reference == null) {
Object value = key.initialValue();
if (this.table == table) {
if (firstTombstone > -1 && table[firstTombstone] == TOMBSTONE) {
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return value;
}
if (table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++;
cleanUp();
return value;
}
}
put(key, value);
return value;
}
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)
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
[// sThreadLocal.set(new Looper(quitAllowed))
如果sThreadLocal.get函数为null, 则说明还没有为当前线程设置过Looper对象,则这里就调用ThreadLocal的set函数来为当前线程new一个Looper对象。
我们先来看一下Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
[// mQueue = new MessageQueue(quitAllowed)
在Looper类中,有一个MessageQueue的成员变量mQueue,定义如下:
final MessageQueue mQueue;
也就是说每一个Looper内部维护了一个MessageQueue。
我们看一下MessageQueue的构造函数:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
[// mPtr = nativeInit()
这里会调用nativeInit()函数。从名字可以猜测这是个native函数。
private native static long nativeInit();
果不其然,确实是个native函数。
调用nativeInit函数其实是调用的android_os_MessageQueue.cpp(为与/home/yaojian/AndroidSource/frameworks/base/core/jni文件夹下)的android_os_MessageQueue_nativeInit函数:
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
[// NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue()
这里会创建一个C++层的NativeMessageQueue的对象。
我们先来看一下NativeMessageQueue的类结构:
class NativeMessageQueue : public MessageQueue
class MessageQueue : public RefBase
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() {
int result = pthread_once(&gTLSOnce, initTLSKey);
[// int result = pthread_once(&gTLSOnce, initTLSKey)
这里这个pthread_once函数是干什么的呢?我也不知道,百度一下查出下面的解释:
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。
也就是说pthread_once保证了initTLSKey函数之调用一次,gTLSOnce和initTLSKey的定义如下:
static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
initTLSKey函数的实现如下:
void Looper::initTLSKey() {
int result = pthread_key_create(&gTLSKey, threadDestructor);
[// int result = pthread_key_create(&gTLSKey, threadDestructor)
在initTLSKey函数中,会调用pthread_key_create函数。那么这个pthread_key_create函数有什么作用么?我也不知道啊?还是百度一下吧:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
函数 pthread_key_create() 用来创建线程私有数据。该函数从 TSD 池中分配一项,将其地址值赋给 key 供以后访问使用。第 2 个参数是一个销毁函数,它是可选的,可以为 NULL,为 NULL 时,则系统调用默认的销毁函数进行相关的数据注销。如果不为空,则在线程退出时(调用 pthread_exit() 函数)时将以 key 锁关联的数据作为参数调用它,以释放分配的缓冲区,或是关闭文件流等。
gTLSKey和threadDestructor的定义如下:
static pthread_key_t gTLSKey = 0;
void Looper::threadDestructor(void *st) {
Looper* const self = static_cast<Looper*>(st);
if (self != NULL) {
self->decStrong((void*)threadDestructor);
}
}
]// int result = pthread_key_create(&gTLSKey, threadDestructor)
LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
}
]// int result = pthread_once(&gTLSOnce, initTLSKey)
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
return (Looper*)pthread_getspecific(gTLSKey);
[// return (Looper*)pthread_getspecific(gTLSKey)
在getForThread函数的最后会调用pthread_getspecific函数。那pthread_getspecific函数是干什么呢?又一次不知道,这次我决定不求助百度了,求助Google:
void *pthread_getspecific(pthread_key_t key);
函数 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 = new Looper(false);
[// mLooper = new Looper(false)
这里会先new一个C++层的Looper对象。我们看一下Looper的构造函数:
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
mIdling = false;
// Allocate the epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
在Looper的构造函数中,会创建两个管道:mWakeReadPipeFd和mWakeWritePipeFd。并且利用epoll机制来设置监听mWakeReadPipeFd。
]// mLooper = new Looper(false)
Looper::setForThread(mLooper);
[// Looper::setForThread(mLooper)
当创建完C++层的Looper对象之后,就可以调用setForThread函数来将该对象设置到当前线程中去。
void Looper::setForThread(const sp<Looper>& looper) {
sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
if (looper != NULL) {
looper->incStrong((void*)threadDestructor);
}
pthread_setspecific(gTLSKey, looper.get());
if (old != NULL) {
old->decStrong((void*)threadDestructor);
}
}
]// Looper::setForThread(mLooper)
}
}
]// NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue()
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
当创建完C++层的NativeMessageQueue之后,就得到这个C++层的NativeMessageQueue的句柄,并赋值给成员变量mPtr. mPtr的定义如下:
private long mPtr; // used by native code
由此得出结论,每一个Java层的MessageQueue对象在C++曾都有一个NativeMessageQueue对象。
]// mPtr = nativeInit()
}
]// mQueue = new MessageQueue(quitAllowed)
mThread = Thread.currentThread();
}
[// private Looper(boolean quitAllowed)
首先我们注意到Looper的构造函数是private的。
]// private Looper(boolean quitAllowed)
当构造完Looper对象之后,就会调用ThreadLocal的set函数来将该Looper对象保存到当前线程的ThreadLocal中去。
我们来看一下ThreadLocal类的set函数的实现:
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
[// public void set(T value)
set函数的实现还是比较清晰的,里面调用的函数我们之前都分析过。
]// public void set(T value)
]// sThreadLocal.set(new Looper(quitAllowed))
}
发表评论
-
Activity与WindowManagerService连接的过程(三)
2018-04-16 16:27 622page11 WindowManagerService ... -
Activity与WindowManagerService连接的过程(二)
2018-04-16 16:36 763page6 WindowManagerGlobal的getW ... -
Activity与WindowManagerService连接的过程(一)
2018-04-16 16:21 984page1 Activity组件在 ... -
Activity的ViewRoot的创建过程(三)
2017-11-06 14:25 739page7 在这篇文章里, 我们分析一下W类的构造过程. W ... -
Activity的ViewRoot的创建过程(二)
2017-11-06 14:29 937page4 我们看一下ViewRootImpl对象的创 ... -
Activity的ViewRoot的创建过程(一)
2017-11-06 14:27 1078page1 当一个Activity第一次激活的时候会为该Ac ... -
Activity的Window和WindowManager的创建过程(三)
2017-07-05 11:49 1334page9 在这里我们分析一下DisplayManager的 ... -
Activity的Window和WindowManager的创建过程(二)
2017-07-05 11:31 543page5 在这篇文章中, 我们分析一下ContextImp ... -
Activity的Window和WindowManager的创建过程(一)
2017-07-05 11:27 605page1 我们开始分析一下Activity的Window和 ... -
Acitivy创建Context的过程(二)
2017-06-21 14:11 512page4 在这里我们分析一下ContextImpl的ini ... -
Acitivy创建Context的过程(一)
2017-06-21 14:15 635page1 从本篇文章开始,我们分析一下Activity创建 ... -
应用程序进程与SurfaceFlinger的连接过程
2017-06-21 11:49 1056我们从SurfaceComposerClient对象的创建开始 ... -
Android源码之SurfaceFlinger的启动(三)
2017-04-20 11:09 1041page11 我们来看一下SurfaceFlinger ... -
Android源码之SurfaceFlinger的启动(二)
2017-04-18 15:15 870page6 我们看一下Thread的run函数的实现: ... -
Android源码之SurfaceFlinger的启动(一)
2017-04-17 10:07 994page1 在Android系统中, 显示系统在底层是通过S ... -
Android源码之Zygote
2015-12-15 11:45 517当ActivityManagerService启动一个应用程序 ... -
Android源码之Binder(五)
2015-12-04 09:19 1508Service组件在启动时,需要将自己注册到Service M ... -
Android源码之Binder(四)
2015-12-04 09:18 1922case BINDER_SET_MAX_THREADS: ... -
Android源码之Binder(三)
2015-12-04 09:17 909{ int ret; struct binder_pr ... -
Android源码之Binder(二)
2015-12-04 09:15 546分析完Binder驱动程序的打开和内存分配的过程之后,我们看一 ...
相关推荐
总结来说,`Android应用源码之HandlerMessage1_HandlerMessage.zip`中的内容可能展示了如何利用`Handler`、`Message`和`Looper`进行多线程间的通信,以确保UI线程的流畅运行。理解和掌握这一机制对于Android开发者来...
本压缩包"Android应用源码之HandlerLooper2_Android.zip"可能包含了关于这个主题的详细示例代码,让我们深入探讨这些关键组件的工作原理。 首先,`Handler`类是Android中处理消息和调度任务的核心组件。它允许...
这个压缩包"安卓Android源码——HandlerMessage3.rar"很可能包含了关于这三者如何协同工作的示例代码或者详细分析。现在,我们将深入探讨这些概念及其在Android系统中的作用。 `Handler` 是一个用于发送和处理消息...
这个压缩包“安卓Android源码——HandlerLooper2.rar”可能包含了关于这些组件的深入分析和示例代码。以下是关于`Handler`、`Looper`和`MessageQueue`的详细解释: 1. **Handler**: - `Handler`是Android中的一个...
本资源"安卓Android源码——HandlerMessage2.rar"可能包含了关于`Handler`和`Message`的深入实践和示例代码,下面我们将详细探讨这些核心组件。 `Handler` 是 Android 中用于在线程间传递消息的对象。它通常用于将...
这个"Android应用源码之HandlerMessage3.zip"压缩包很可能是包含了一个示例项目,详细展示了HandlerMessage的用法。现在我们来深入探讨一下Handler、Message以及它们在Android中的作用。 **1. Handler(处理器)** ...
这个压缩包“Android应用源码之HandlerMessage3_Android.zip”显然包含了一个示例,演示了如何在Android应用中有效地使用这些组件。 首先,我们来深入理解Handler。Handler是Android中处理消息和异步任务的类,它...
这个压缩包“Android应用源码之HandlerLooper1_Android.zip”可能包含了一个示例项目,详细展示了如何在Android应用程序中使用这些组件。 首先,我们来深入理解`Handler`。`Handler`是Android中的一个关键类,主要...
在Android应用开发中,Handler和Message是实现线程间通信的关键机制。本压缩包"Android应用源码之...深入研究"Android应用源码之HandlerMessage2_应用.zip"中的示例代码,有助于提升对这一关键机制的理解和应用能力。
Android应用源码之HandlerMessage3.zip项目安卓应用源码下载Android应用源码之HandlerMessage3.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
Android应用源码之HandlerMessage2.zip项目安卓应用源码下载Android应用源码之HandlerMessage2.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
Android应用源码之HandlerMessage1.zip项目安卓应用源码下载Android应用源码之HandlerMessage1.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
Android应用源码之HandlerLooper2.zip项目安卓应用源码下载Android应用源码之HandlerLooper2.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
Android应用源码之HandlerLooper1.zip项目安卓应用源码下载Android应用源码之HandlerLooper1.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
`Android应用源码之HandlerLooper2.zip`可能包含了一个示例项目,用于演示如何有效使用这些组件。以下是对这些核心概念的详细说明: 1. **Handler**: `Handler` 是一个用于在特定线程(通常是UI线程)中发送和...
【Android应用源码之HandlerMessage1.zip】是一个与Android应用程序开发相关的压缩包,重点在于讲解Handler和Message在Android系统中的使用。在这个项目中,我们可能会看到一个简单的Android应用实例,该实例展示了...
本资料“Android应用源码之HandlerLooper1.zip”应该是包含了一个关于这些组件的详细示例或分析,让我们来深入探讨它们的工作原理。 首先,`Handler`是Android中的一个类,它用于在UI线程中发送和处理消息。当你...
在Android系统中,Handler、Looper和Message构成了一个用于线程间通信的重要机制。这个机制使得UI线程可以处理来自其他线程的消息,从而避免了直接在非UI线程操作UI组件,防止应用出现ANR(Application Not ...
`Handler`是Android中的一个类,它允许开发者在不同的线程中发送和处理消息。通常,我们在主线程(UI线程)中创建一个`Handler`实例,然后在这个`Handler`中定义消息处理逻辑。通过`sendMessage()`或`post(Runnable)...
www.mars-droid.com/Android开发视频教程 代码 源码 mars老师讲课 android 视频源码 Handler ProgressBarHandler(在此特别感谢mars的无私奉献,此代码为跟随视频边学边做的)