Android 如何在jni层使用Looper
Posted Alex_MaHao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 如何在jni层使用Looper相关的知识,希望对你有一定的参考价值。
概述
假设现在有这样一个需求:在c++层进行定时任务,然后任务回调到主线程运行。对于在java层通过handler.postDelay()就可以实现。而在c层呢?
两种思路:
- 通过jni反调java层的
handler
方法做处理。 - 在jni层获取到对应c++主线程的looper,然后进行处理
第一种方式实现上很简单。第二种方式google提供了jni层对应的库,地址https://developer.android.com/ndk/reference/group/looper#group___looper_1ga2668285bfadcf21ef4d371568a30be33
使用
假设想定时检测gps的有无,有如下文件
CheckGpsTask.h
#ifndef C_LOOP_DEMO_CHECKGPSTASK_H
#define C_LOOP_DEMO_CHECKGPSTASK_H
class CheckGpsTask
public:
void checkGps();
virtual void start();
;
#endif //C_LOOP_DEMO_CHECKGPSTASK_H
start()
方法用于开启定时任务,checkGps
用于在主线程中运行。
定义一个子类androidCheckAdapter
,以便后期适配ios。
AndroidCheckAdapter.h
#ifndef C_LOOP_DEMO_ANDROIDCHECKADAPTER_H
#define C_LOOP_DEMO_ANDROIDCHECKADAPTER_H
#include <android/looper.h>
#include "CheckGpsTask.h"
class AndroidCheckAdapter : public CheckGpsTask
public:
ALooper *mainThreadLooper;
// 用以监听事件
int readPipe = -1;
int writePipe = -1;
AndroidCheckAdapter();
~AndroidCheckAdapter();
void start();
;
#endif //C_LOOP_DEMO_ANDROIDCHECKADAPTER_H
mainThreadLooper
是调用jni的默认线程,通过一定方式获取。
pipe
是管道相关,用于监听读写事件。
具体实现
AndroidCheckGpsAdapter.cpp
#include "AndroidCheckAdapter.h"
#include <android/looper.h>
#include <unistd.h>
#include <thread>
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, "loop", __VA_ARGS__)
// 当管道有写入时的回调
int callback(int fd, int events, void *data)
char msg;
read(fd, &msg, 1);
((AndroidCheckAdapter *) data)->checkGps();
// AndroidCheckAdapter::getInstance()->checkGps();
// 返回1表示持续接收事件
return 1;
AndroidCheckAdapter::AndroidCheckAdapter()
// 初始化操作
mainThreadLooper = ALooper_forThread();
if (mainThreadLooper != NULL)
ALooper_acquire(mainThreadLooper);
int messagePipe[2];
int result = pipe(messagePipe);
if (result == -1)
return;
readPipe = messagePipe[0];
writePipe = messagePipe[1];
LOGI("readPipe %d - writePipe %d", readPipe, writePipe);
// 添加监听
ALooper_addFd(mainThreadLooper, readPipe,
0, ALOOPER_EVENT_INPUT, callback, this);
AndroidCheckAdapter::~AndroidCheckAdapter()
// 释放资源
if (mainThreadLooper != NULL && readPipe != -1)
ALooper_removeFd(mainThreadLooper, readPipe);
ALooper_release(mainThreadLooper);
if (readPipe != -1)
close(readPipe);
if (writePipe != -1)
close(writePipe);
void AndroidCheckAdapter::start()
// 开启子线程
std::thread worker([this]()
for (char msg = 0; msg < 110; msg++)
LOGI("send : %s",
std::string("tid:").append(std::to_string(gettid())).c_str());
// 写入消息,更新管道
write(writePipe, &msg, 1);
sleep(1);
);
worker.detach();
按照流程如下:
获取主线程的Looper
对象,并获取引用,防止被销毁。
mainThreadLooper = ALooper_forThread();
ALooper_acquire(mainThreadLooper);
创建管道,并监听回调
int messagePipe[2];
int result = pipe(messagePipe);
if (result == -1)
return;
readPipe = messagePipe[0];
writePipe = messagePipe[1];
LOGI("readPipe %d - writePipe %d", readPipe, writePipe);
/**
* ALooper*:mainThreadLooper:loop对象
* fd:readPipe:监听读入管道
* ident:主要用于poll的方式监听,如果后面的callback不为null,则该字段被忽视
* events:ALOOPER_EVENT_INPUT 监听的事件类型
* ALooper_callbackFunc:callback,当有输入事件时的回调
* data:数据指针
*/
ALooper_addFd(mainThreadLooper, readPipe,
0, ALOOPER_EVENT_INPUT, callback, this);
开启线程,往管道中写入数据
void AndroidCheckAdapter::start()
// 开启子线程
std::thread worker([this]()
for (char msg = 100; msg < 110; msg++)
LOGI("send : %s",
std::string("tid:").append(std::to_string(gettid())).c_str());
// 写入数据
write(writePipe, &msg, 1);
sleep(1);
);
worker.detach();
回调被执行
int callback(int fd, int events, void *data)
char msg;
read(fd, &msg, 1);
((AndroidCheckAdapter *) data)->checkGps();
// 返回1表示持续接收事件
return 1;
以上是关于Android 如何在jni层使用Looper的主要内容,如果未能解决你的问题,请参考以下文章