You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 20:45:03