如何在Android C++中自行实现looper,而非使用系统ALooper类?
Android平台自定义Looper及MessageQueue实现方案
Looper的核心本质是线程绑定的循环调度器,通过绑定专属的消息队列完成阻塞等待、消息分发逻辑,完全可以绕开系统原生ALooper接口自行实现,步骤如下:
核心组件定义
你需要先定义三个核心结构体,所有逻辑自行控制:
Message:承载消息数据的单元,包含消息标识、参数、自定义数据指针、触发时间戳、处理回调、链表指针等字段MessageQueue:按触发时间排序的消息链表,搭配互斥锁、条件变量实现线程安全的入队、出队、阻塞唤醒逻辑Looper:和线程唯一绑定的循环器,持有消息队列实例、退出标志位,通过线程局部存储(TLS)保证单线程唯一
核心接口实现
1. Message 工具方法
首先实现消息池复用逻辑,避免频繁内存申请/释放:
// 消息结构体定义 typedef struct Message { int what; int arg1; int arg2; void* userData; long when; // 触发时间,建议用单调时间戳 void (*callback)(struct Message*); struct Message* next; } Message; // 全局消息池(需加锁访问) static Message* gMessagePool = NULL; static pthread_mutex_t gPoolLock = PTHREAD_MUTEX_INITIALIZER; // 从消息池获取空闲Message Message* obtainMessage() { pthread_mutex_lock(&gPoolLock); Message* msg = NULL; if (gMessagePool != NULL) { msg = gMessagePool; gMessagePool = msg->next; memset(msg, 0, sizeof(Message)); } else { msg = malloc(sizeof(Message)); memset(msg, 0, sizeof(Message)); } pthread_mutex_unlock(&gPoolLock); return msg; } // 回收用完的Message到消息池 void recycleMessage(Message* msg) { pthread_mutex_lock(&gPoolLock); msg->next = gMessagePool; gMessagePool = msg; pthread_mutex_unlock(&gPoolLock); }
2. MessageQueue 实现
核心实现入队、出队两个操作,注意线程同步:
typedef struct MessageQueue { Message* mHead; pthread_mutex_t mLock; pthread_cond_t mCond; bool mQuit; } MessageQueue; // 初始化队列 MessageQueue* createMessageQueue() { MessageQueue* queue = malloc(sizeof(MessageQueue)); memset(queue, 0, sizeof(MessageQueue)); pthread_mutex_init(&queue->mLock, NULL); pthread_cond_init(&queue->mCond, NULL); queue->mQuit = false; return queue; } // 消息入队,按when升序插入 bool enqueueMessage(MessageQueue* queue, Message* msg, long when) { pthread_mutex_lock(&queue->mLock); if (queue->mQuit) { pthread_mutex_unlock(&queue->mLock); recycleMessage(msg); return false; } msg->when = when; Message* p = queue->mHead; if (p == NULL || when < p->when) { // 插入队首,需要唤醒阻塞的Looper msg->next = p; queue->mHead = msg; pthread_cond_signal(&queue->mCond); } else { // 找到合适位置插入 Message* prev; do { prev = p; p = p->next; } while (p != NULL && p->when <= when); msg->next = prev->next; prev->next = msg; } pthread_mutex_unlock(&queue->mLock); return true; } // 消息出队,无消息时阻塞 Message* next(MessageQueue* queue) { long nextWaitTime = 0; while (true) { pthread_mutex_lock(&queue->mLock); if (queue->mQuit) { pthread_mutex_unlock(&queue->mLock); return NULL; } Message* head = queue->mHead; if (head != NULL) { long now = getCurrentMonotonicTimeMs(); // 可通过clock_gettime(CLOCK_MONOTONIC)实现 if (now >= head->when) { // 时间到,取出消息 queue->mHead = head->next; pthread_mutex_unlock(&queue->mLock); return head; } else { // 计算等待时长 nextWaitTime = head->when - now; } } else { // 队列空,无限等待 nextWaitTime = -1; } // 阻塞等待 if (nextWaitTime < 0) { pthread_cond_wait(&queue->mCond, &queue->mLock); } else { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec += nextWaitTime / 1000; ts.tv_nsec += (nextWaitTime % 1000) * 1000000; pthread_cond_timedwait(&queue->mCond, &queue->mLock, &ts); } pthread_mutex_unlock(&queue->mLock); } }
3. Looper 实现
通过pthread线程局部存储实现单线程唯一Looper绑定,替代你不想使用的原生ALooper_prepare调用:
// 线程局部存储key,每个线程存储自己的Looper指针 static pthread_key_t gLooperKey; static pthread_once_t gKeyOnce = PTHREAD_ONCE_INIT; static void createLooperKey() { pthread_key_create(&gLooperKey, NULL); } typedef struct Looper { MessageQueue* mQueue; bool mQuit; } Looper; // 初始化当前线程的Looper,替代原生ALooper_prepare Looper* Looper_prepare() { pthread_once(&gKeyOnce, createLooperKey); if (pthread_getspecific(gLooperKey) != NULL) { // 每个线程只能有一个Looper return NULL; } Looper* looper = malloc(sizeof(Looper)); looper->mQueue = createMessageQueue(); looper->mQuit = false; pthread_setspecific(gLooperKey, looper); return looper; } // 获取当前线程的Looper Looper* Looper_myLooper() { pthread_once(&gKeyOnce, createLooperKey); return pthread_getspecific(gLooperKey); } // 启动Looper循环 void Looper_loop() { Looper* looper = Looper_myLooper(); if (looper == NULL) return; while (!looper->mQuit) { Message* msg = next(looper->mQueue); if (msg == NULL) { // 队列退出,结束循环 break; } // 分发消息 if (msg->callback != NULL) { msg->callback(msg); } else { // 自行实现其他分发逻辑,比如调用target的处理方法 } recycleMessage(msg); } } // 退出Looper void Looper_quit(Looper* looper, bool safe) { pthread_mutex_lock(&looper->mQueue->mLock); looper->mQuit = true; looper->mQueue->mQuit = true; // 清空队列,safe模式可以保留未触发的消息自行处理 Message* p = looper->mQueue->mHead; while (p != NULL) { Message* next = p->next; recycleMessage(p); p = next; } looper->mQueue->mHead = NULL; pthread_cond_signal(&looper->mQueue->mCond); pthread_mutex_unlock(&looper->mQueue->mLock); }
注意事项
- 时间戳必须使用单调时间,不要用系统 wall time,避免系统时间修改导致延迟消息调度异常
- 所有操作消息队列、消息池的逻辑都要加锁,避免多线程并发的竞态问题
- 消息回收逻辑要覆盖所有场景,避免Native层内存泄漏
- 线程退出前必须调用
Looper_quit,否则会出现线程泄漏
内容的提问来源于stack exchange,提问作者Nguyễn Châu
相关产品推荐
相关产品推荐

