基于@Sergio的答案,这里提供一个简单的包装器
NativeHandler
,它可以接受函数、函数对象和lambda作为参数,并尝试模拟
android.os.Handler
的行为。
class NativeHandler {
public:
static constexpr auto TAG = "NativeHandler";
static NativeHandler* forCurrentThread() {
return new NativeHandler;
}
template<typename FUNC, typename... ARGS>
bool post(FUNC&& func, ARGS&&... args) {
auto callable = new Callable(func, std::forward<ARGS>(args)...);
write(_pipeFDS[1], &callable, sizeof(decltype(callable)));
return true;
}
NativeHandler(const NativeHandler&) = delete;
NativeHandler(NativeHandler&&) = delete;
NativeHandler& operator=(const NativeHandler&) = delete;
NativeHandler& operator=(NativeHandler&&) = delete;
virtual ~NativeHandler() {
ALooper_removeFd(_looper, _pipeFDS[0]);
ALooper_release(_looper);
close(_pipeFDS[0]);
close(_pipeFDS[1]);
}
private:
class Callable {
public:
void call() {
if (_function) _function();
}
template<typename FUNC, typename... ARGS>
Callable(FUNC func, ARGS... args) : _function(std::bind(func, args...)) {}
Callable() = delete;
Callable(const Callable&) = delete;
Callable(Callable&&) = delete;
Callable operator=(const Callable&) = delete;
Callable operator=(Callable&&) = delete;
virtual ~Callable() {}
private:
std::function<void()> _function;
};
NativeHandler() {
if (pipe(_pipeFDS) != 0) {
throw std::bad_alloc();
}
_looper = ALooper_forThread();
ALooper_acquire(_looper);
if (ALooper_addFd(_looper, _pipeFDS[0], ALOOPER_POLL_CALLBACK,
ALOOPER_EVENT_INPUT, _looperCallback, nullptr) == -1) {
throw std::bad_alloc();
}
};
ALooper* _looper;
int _pipeFDS[2];
static int _looperCallback(int fd, int events, void* data) {
void* buf = new char[sizeof(Callable*)];
ssize_t nr = read(fd, buf, sizeof(Callable*));
Callable* callable = *((Callable**)buf);
__android_log_print(ANDROID_LOG_INFO, "Callable", "read size is %d %p", nr, callable);
callable->call();
delete[] buf;
return 1;
}
};
以下是使用示例,希望对任何想要在JNI中实现类似于Android Java API Handler的行为的人有所帮助。
void f(char c, short s) {
__android_log_print(ANDROID_LOG_DEBUG, NativeHandler::TAG, "%s c = %c, s = %d", __FUNCTION__, c, s);
}
struct Task {
void operator()(int i, double d) {
__android_log_print(ANDROID_LOG_DEBUG, NativeHandler::TAG, "Task i = %d, d = %f", i, d);
}
};
auto handler = NativeHandler::forCurrentThread();
std::thread worker([handler]() {
handler->post([](int i, double d, void* p) {
__android_log_print(ANDROID_LOG_DEBUG, "NativeHandler", "i = %d, d = %f, p = %p", i, d, p);
}, 100, -123.4, nullptr);
handler->post(f, 'c', 128);
handler->post(Task(), 123, 3.1415926);
});
worker.detach();