C++ 实现Android Handler机制

前言:

        一直使用android的Handler,非常方便好用,但是当我使用C++编程时,想使用Android Handler一样的编程模式,竟不知如何下手,网上找了很久,都没找到具体的实现,也可能是我找的不够多。这两天沉下心来自己写了一个,省的自己去找了,以后肯定还能用到,最好有网友也做了类似实现,我可以借鉴下以提升自己。

代码参考Android Handler,有兴趣的朋友可以去看看Android 里面的实现。Android Handler 使用epoll 实现,我这里做了个简化版本,使用条件变量实现。

handler.h

#pragma once

#include "message.h"
#include <chrono>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <mutex>
#include <thread>

using namespace std;
/*
 * Handler will run in it's own thread, you don't want to care about it.
 * Message will be proccess by the Handler. Two ways to add your task to the Handler.
 * 1. send message to the handler
 * 2. post the task(Function) to handler
 */
namespace es {
class Handler {
public:
    using TimePoint_t      = std::chrono::steady_clock::time_point;
    using Clock_t          = std::chrono::steady_clock;
    using MillisDuration_t = std::chrono::milliseconds;
    using Task             = std::function<void(const Message &msg)>;

    Handler();
    ~Handler() {
        is_stop = true;
        condition.notify_all();
        looper.join();
    }

    bool sendEmptyMessageDelay(int what, long delayMillis);
    bool sendEmptyMessageDelay(int what) { return sendEmptyMessageDelay(what, 0); }
    bool postDelay(function<void()> &&f, long delayMillis);
    bool post(std::function<void()> &&f) { return postDelay(std::move(f), 0); }
    void removeMessages(int what) {
        if (what < 0) return;

        std::unique_lock<std::mutex> lock(queue_mutex);
        if (!msg_list.empty()) msg_list.remove_if([what](const Message &m) { return m.what == what; });
    }
    void removeAlls() {
        std::unique_lock<std::mutex> lock(queue_mutex);
        if (!msg_list.empty()) msg_list.clear();
    }
    void stop() {
        is_stop = true;
        condition.notify_one();
    }

    void handleMessage(Task &&cb) { callback = cb; }

private:
    void dispatchMessage(const Message &msg) const;

private:
    bool               is_stop;
    list<Message>      msg_list;
    mutex              queue_mutex;
    condition_variable condition;
    thread             looper;
    Task               callback;
};
} // namespace es

handler.cc

#include "handler.h"
#include "message.h"
#include <algorithm>
#include <chrono>
#include <iostream>

namespace es {
Handler::Handler()
    : is_stop(false), looper([this]() {
          for (;;) {
              Message msg;
              bool    isFired = false;
              {
                  std::unique_lock<std::mutex> lock(this->queue_mutex);
                  if (this->msg_list.empty()) {
                      this->condition.wait(lock, [this] { return this->is_stop || !this->msg_list.empty(); });
                  } else {
                      this->condition.wait_until(lock, this->msg_list.front().when,
                                                 [this] { return this->is_stop || this->msg_list.empty(); });
                  }

                  if (!is_stop && this->msg_list.empty()) continue;
                  if (is_stop) {
                      msg_list.clear();
                      return;
                  }

                  if (msg_list.front().when < Clock_t::now()) {
                      msg = std::move(msg_list.front());
                      msg_list.pop_front();
                      isFired = true;
                  }
              }
              if (isFired) this->dispatchMessage(msg);
          }
      }) {}

bool Handler::sendEmptyMessageDelay(int what, long delayMillis) {

    if (what < 0 || delayMillis < 0) return false;
    Message msg(what, delayMillis);

    std::unique_lock<std::mutex> lock(queue_mutex);
    msg_list.push_back(msg);
    // 跟进时间进行降序排列
    msg_list.sort(std::less<Message>());
    condition.notify_one();
    return true;
}

bool Handler::postDelay(std::function<void()> &&f, long delayMillis) {
    if (f == nullptr || delayMillis < 0) {
        return false;
    }

    std::unique_lock<std::mutex> lock(queue_mutex);
    Message                      msg(0, delayMillis);
    msg.onRun(std::move(f));
    msg_list.push_back(msg);
    msg_list.sort(std::less<Message>());
    return true;
}

void Handler::dispatchMessage(const Message &msg) const {
    if (msg.task != nullptr) {
        msg.task();
    } else {
        if (msg.what < 0 || callback == nullptr) return;
        callback(msg);
    }
}

} // namespace es

使用:

#include <iostream>
#include <memory>

#include "handler.h"
#include "message.h"

using namespace std;
using namespace es;

int main(int argc, char **argv) {
    cout << "Handler tutorial" << endl;

    Handler hdlr;
    hdlr.handleMessage([](const Message &msg) {
        switch (msg.what) {
        case 0: break;

        case 1: break;

        default: break;
        }

        cout << "Handler what: " << msg.what << endl;
    });
    for (int i = 0; i < 6; i++) {
        hdlr.sendEmptyMessageDelay(i + 1, 1000 * i);
    }

    hdlr.postDelay([]() { cout << "POST call back" << endl; }, 230);

    std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::seconds(3));
    hdlr.removeMessages(6);
    std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::seconds(1));
    hdlr.removeAlls();
    // hdlr.stop();
    cout << "Program exit !" << endl;
    return 1;
}

这里只帖出Handler的实现,还有个配套的Message实现,感兴趣的童鞋自己去下面链接查看吧。

代码链接:https://github.com/feekia/EventServer

另,转载请注明出处:CSDN

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值