概述
假設現在有這樣一個需求:在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;
}