1. 程式人生 > >C++ 模仿Android實現Handler機制

C++ 模仿Android實現Handler機制

前言:

        一直使用android的Handler,感覺非常好用,但是當我使用C++程式設計時,想使用Android Handler一樣的程式設計模式,竟不知如何下手,網上找了很久,都沒找到具體的實現,能搜尋到MFC中使用handler,但是一直不搞windows的開發,也不曉得上哪兒去弄,也可能是我找的不夠多吧。這個Handler已經嚴重的影響了我,沒有它左右不舒服。這兩天沉下心來自己寫了一個,省的自己去找了,以後肯定還能用到,最好有網友也做了類似實現,我可以借鑑下以提升自己。

程式碼參考Android Handler,有興趣的朋友可以去看看Android 裡面的實現。

Handler.h

#pragma once
#ifndef HANDLER_H
#define HANDLER_H

#include <chrono>
#include <map>
#include <mutex>
#include <vector>
#include <thread>


#include "Message.h"

/*
 * 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
 */

class Handler{
public:
	Handler();
	virtual ~Handler();

	bool sendMessageAtTime(Message& msg, long uptimeMillis);
	bool sendMessage(Message& msg);
	bool sendEmptyMessage(int what);
	bool sendEmptyMessage(int what, long uptimeMillis);

	bool post(Message::Function f);
	bool postAtTime(Message::Function f, long uptimeMillis);

	void removeMessages(int what);
	void removeCallbackAndMessages();

	void stopSafty(bool stopSafty);

	bool isQuiting();

	virtual void handleMessage(Message& msg);

	void dispatchMessage(Message& msg);

	/*
	 * for msgQueue sorted when insert,
	 * ascending order
	 */
	template<class T>
	class ValComp {
	public:
		bool operator()(const T& t1,const T& t2) const {
			return (t1 < t2);
		}

	};

private:
	std::vector<Message> msg_Q;

	std::mutex queue_mutex;
	std::condition_variable condition;
	std::thread looper;
	bool stop;
	bool stopWhenEmpty;
};

#endif

Handler.cpp

#include <chrono>
#include <algorithm>
#include <iostream>
#include "Handler.h"
#include "Message.h"
#define LOGENTER (std::cout << "This is FUNCTION " << __func__<<  std::endl)
Handler::Handler():stop(false),stopWhenEmpty(false){
	looper = std::thread(
		[this](){
			for(;;)
			{
				Message msg;
				{
					std::unique_lock<std::mutex> lock(this->queue_mutex);
					if(this->msg_Q.empty()){
						this->condition.wait(lock, [this]{ return this->stop || this->stopWhenEmpty || !this->msg_Q.empty();});
					}else{
						this->condition.wait_until(lock, this->msg_Q.back().when, [this]{ return this->stop || this->stopWhenEmpty || !this->msg_Q.empty(); });
					}

					if(this->stopWhenEmpty && this->msg_Q.empty())
						return;
					if(stop){
						msg_Q.clear();
						return;
					}

					msg = std::move(msg_Q.back());
					msg_Q.pop_back();
				}
				this->dispatchMessage(msg);
			}
		});
}
Handler::~Handler(){
	{
		std::unique_lock<std::mutex> lock(queue_mutex);
		stop = true;
	}
	condition.notify_all();
	looper.join();
	msg_Q.clear();

}

void Handler::handleMessage(Message& msg){
	std::cout << "IN Handler " << __func__<< " what:" << msg.m_what <<  std::endl;
}

bool Handler::sendMessageAtTime(Message& msg, long uptimeMillis){
	if(uptimeMillis < 0 )
		return false;

	msg.setWhen(uptimeMillis);

	std::unique_lock<std::mutex> lock(queue_mutex);
	auto i = std::find(msg_Q.begin(),msg_Q.end(),msg);
	msg_Q.erase(i);

	msg_Q.push_back(msg);
	std::sort(msg_Q.begin(), msg_Q.end(),std::greater<Message>());
	condition.notify_one();
	return true;
}
bool Handler::sendMessage(Message& msg){
	return false;

	std::unique_lock<std::mutex> lock(queue_mutex);
	auto i = find(msg_Q.begin(),msg_Q.end(),msg);
	if(i != msg_Q.end())
		msg_Q.erase(i);

	msg_Q.push_back(msg);
	std::sort(msg_Q.begin(), msg_Q.end(),std::greater<Message>());
	condition.notify_one();
	return true;
}

bool Handler::sendEmptyMessage(int what){
	return sendEmptyMessage(what ,0);
}

bool Handler::sendEmptyMessage(int what,long uptimeMillis){

	if(what < 0 || uptimeMillis < 0)
		return false;

	Message msg(what);
	msg.setWhen(uptimeMillis);

	std::unique_lock<std::mutex> lock(queue_mutex);

	std::vector<Message>::iterator i = find(msg_Q.begin(),msg_Q.end(),msg);
	if (i != msg_Q.end()){
		msg_Q.erase(i);
	}

	msg_Q.push_back(msg);
//	std::sort(msg_Q.begin(), msg_Q.end(),ValComp<Message>());
	// 跟進時間進行降序排列
	std::sort(msg_Q.begin(), msg_Q.end(),std::greater<Message>());

	condition.notify_one();
	return true;
}

bool Handler::post(Message::Function f){
	return postAtTime(f,0);
}
bool Handler::postAtTime(Message::Function f, long uptimeMillis){

	if(f == nullptr || uptimeMillis < 0){
		return false;
	}

	std::unique_lock<std::mutex> lock(queue_mutex);
	Message msg;
	msg.setWhen(uptimeMillis);
	msg.setFunction(f);
	msg_Q.push_back(msg);
	std::sort(msg_Q.begin(), msg_Q.end(),std::greater<Message>());

	return true;
}

void Handler::removeMessages(int what){
	if(what < 0)
		return;

	std::unique_lock<std::mutex> lock(queue_mutex);

	auto i = find(msg_Q.begin(),msg_Q.end(),what);
	if (i != msg_Q.end()){
		msg_Q.erase(i);
	}

	condition.notify_one();
}

void Handler::removeCallbackAndMessages(){
	std::unique_lock<std::mutex> lock(queue_mutex);
	msg_Q.clear();
}

void Handler::stopSafty(bool stopSafty){
	std::unique_lock<std::mutex> lock(queue_mutex);
	if(stopSafty){
		stopWhenEmpty = true;
	}else{
		stop = true;
	}
}


bool Handler::isQuiting(){
	std::unique_lock<std::mutex> lock(queue_mutex);
	if(stop || stopWhenEmpty)
		return true;
	return false;
}

void Handler::dispatchMessage(Message& msg){
	if(msg.task != nullptr){
		msg.task();
	}else{
		if(msg.m_what < 0)
			return;
		handleMessage(msg);
	}
}

使用:

class myHandler : public Handler{
	virtual void handleMessage(Message& msg) override {
		Handler::handleMessage(msg);
		switch(msg.m_what){
		case 0:

			break;

		case 1:
			break;

		case 2:
			break;

		case 3:
			break;

		case 4:
			break;

		case 5:
			break;

		default:
			break;
		}

		cout << "IN myHandler case: " << msg.m_what << endl;
	}
};
int main(int argc, char **argv)
{
	cout << "IN main" << endl;

	myHandler hdlr;
	for(int i = 0; i < 6; i++){
		hdlr.sendEmptyMessage(i, 100 * i);
	}

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

	hdlr.stopSafty(true); //停止handler,在停止前處理完所有訊息
	while(true){
		std::this_thread::sleep_for(std::chrono::seconds(100000));
	}
	return 1;
}

這裡只帖出Handler的實現,還有個配套的Message實現,感興趣的童鞋自己去下面連結檢視吧。

程式碼連結:https://github.com/feekia/EventServer