电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制

瀏覽:58日期:2022-09-24 17:34:08

使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制

封面出自:板栗懶得很背景

線程作為系統(tǒng)的基礎(chǔ)資源,相信大多數(shù)讀者都有使用到。一般情況下我們會(huì)直接開一個(gè)線程做一些耗時(shí)操作,處理完之后讓線程自動(dòng)結(jié)束,資源被系統(tǒng)回收。這種簡(jiǎn)單粗暴的方法不少讀者、甚至一些大廠的APP都在用。以Java語言為例,我們可以直接new一個(gè)Thread對(duì)象,然后覆蓋run方法,最后調(diào)一下start方法便可以成功運(yùn)行一個(gè)線程。如果我們每次異步做一些耗時(shí)處理都單獨(dú)開啟一個(gè)線程,比如異步加載網(wǎng)絡(luò)圖片這種高并發(fā)操作,每張圖片都開一個(gè)線程的話,必然會(huì)造成線程資源的浪費(fèi),而且也沒有很好的方法去處理跨線程通訊的問題。由于語言層面的低成本導(dǎo)致系統(tǒng)的線程資源被濫用,已經(jīng)成為了一個(gè)很普遍的現(xiàn)象。

new Thread(){ @Override public void run() { //Do somethings }}.start()

Handler

  Handler機(jī)制通過開啟一個(gè)子線程,并進(jìn)入死循環(huán),不停消費(fèi)其它線程發(fā)送過來的消息,從而達(dá)到跨線程通訊的目的。Handler主要用于跨線程通訊,但同時(shí)也能在一定程度上復(fù)用線程,是一種比較理想的線程使用方式。Android系統(tǒng)Handler主要包含以下三部分:

Handler Looper Message & MessageQueue

Handler顧名思義就是消息的處理類,同時(shí)也是消息發(fā)送的代理入口,通過調(diào)用Handler的相關(guān)接口發(fā)送一條消息,最終會(huì)被轉(zhuǎn)發(fā)到Looper,由Looper把Message加入到隊(duì)列的尾部。Looper是消息循環(huán)驅(qū)動(dòng)的動(dòng)力所在,我們規(guī)定同一個(gè)線程只能擁有一個(gè)Looper,當(dāng)Looper準(zhǔn)備好之后會(huì)讓線程進(jìn)入死循環(huán),如果內(nèi)部的Message隊(duì)列不為空時(shí),則會(huì)不停的從消息隊(duì)列頭部取出一條Message進(jìn)行消費(fèi),直到隊(duì)列為空,Looper阻塞線程進(jìn)入等待狀態(tài)。Message內(nèi)部會(huì)記錄著發(fā)送消息的Handler,當(dāng)被消費(fèi)時(shí)就可以找到對(duì)應(yīng)的Handler進(jìn)行消息處理,最終形成閉環(huán)。

使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制

實(shí)現(xiàn)

下面嘗試使用C++11來實(shí)現(xiàn)Android系統(tǒng)Handler機(jī)制,該實(shí)現(xiàn)主要由AlHandlerThread、AlHandler、AlLooperManager、AlLooper、AlMessageQueue和AlMessage六個(gè)類組成。我們規(guī)定一個(gè)線程只能擁有一個(gè)AlLooper,因此需要一個(gè)AlLooperManager負(fù)責(zé)對(duì)所有線程的AlLooper對(duì)象進(jìn)行管理,如果當(dāng)前線程已經(jīng)擁有了AlLooper對(duì)象,則直接使用當(dāng)前線程的對(duì)象,保證AlLooper唯一。而AlMessageQueue則是一個(gè)支持線程阻塞和喚醒的消息隊(duì)列。AlHandlerThread則是一個(gè)封裝了std::thread和AlLooper的簡(jiǎn)單線程實(shí)現(xiàn),僅僅是為了方便使用AlLooper,與Android系統(tǒng)中的HandlerThread實(shí)現(xiàn)是一致的。

使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制

AlHandler

AlHandler提供兩個(gè)構(gòu)造函數(shù),第一個(gè)只有Callback參數(shù),該構(gòu)造函數(shù)會(huì)默認(rèn)獲取當(dāng)前線程的AlLooper,如果當(dāng)前沒有AlLooper,則會(huì)拋出異常。第二個(gè)構(gòu)造函數(shù)支持傳入一個(gè)AlLooper,該AlLooper對(duì)象將會(huì)從AlHandlerThread獲取。sendMessage函數(shù)負(fù)責(zé)把AlMessage轉(zhuǎn)發(fā)到AlLooper,值得注意的是,在發(fā)送到AlLooper之前會(huì)先給AlMessage的成員變量target賦值,也就是當(dāng)前AlHandler對(duì)象的指針。dispatchMessage函數(shù)用于在AlLooper中消費(fèi)消息。

class AlHandler {public: typedef function<void(AlMessage *msg)> Callback;public: AlHandler(Callback callback); AlHandler(AlLooper *looper, Callback callback); void sendMessage(AlMessage *msg) { _enqueueMessage(msg); } void dispatchMessage(AlMessage *msg) { if (callback) { callback(msg); } }private: void _enqueueMessage(AlMessage *msg) { if (this->looper) { msg->target = this; this->looper->sendMessage(msg); } }private: AlLooper *looper = nullptr; Callback callback = nullptr;};

AlLooperManager

AlLooperManager只有一個(gè)功能,那就是管理所有創(chuàng)建的AlLooper對(duì)象,所以它是一個(gè)單例,代碼雖然簡(jiǎn)單,但卻很重要。由于操作系統(tǒng)會(huì)為每一個(gè)線程分配一個(gè)唯一的tid(Thread ID,Linux下可以使用pthread_self獲取到),所以我們可以通過tid的唯一性來管理所有線程創(chuàng)建的AlLooper對(duì)象。該類的create和get函數(shù)分別用于創(chuàng)建新的AlLooper對(duì)象,以及獲取緩存的對(duì)象。創(chuàng)建一個(gè)對(duì)象時(shí)首先需要檢查緩存中是否存在該線程對(duì)應(yīng)的AlLooper,如果已經(jīng)存在則應(yīng)該避免重復(fù)創(chuàng)建,直接返回空指針即可。而get函數(shù)用于從緩存中獲取一個(gè)對(duì)象,如果緩存中沒有則返回空指針。remove用于銷毀一個(gè)AlLooper,一般會(huì)在線程銷毀時(shí)使用。這幾個(gè)函數(shù)都需要保證線程安全。

private: AlLooperManager() : Object() {} AlLooperManager(AlLooperManager &e) : Object() {} ~AlLooperManager() {} /** * 為當(dāng)前線程創(chuàng)建Looper * @return 當(dāng)前線程的Looper */ AlLooper *create(long tid) { std::lock_guard<std::mutex> guard(mtx); auto it = looperMap.find(tid); if (looperMap.end() == it) { auto *looper = new AlLooper(); looperMap[tid] = looper; return looper; } return nullptr; } /** * 獲取當(dāng)前線程的Looper * @return 當(dāng)前線程的Looper */ AlLooper *get(long tid) { std::lock_guard<std::mutex> guard(mtx); auto it = looperMap.find(tid); if (looperMap.end() == it) { return nullptr; } return it->second; } /** * 銷毀當(dāng)前線程的Looper */ void remove(long tid) { std::lock_guard<std::mutex> guard(mtx); auto it = looperMap.find(tid); if (looperMap.end() != it) { looperMap.erase(it); auto *looper = it->second; delete looper; } }private: static AlLooperManager *instance; std::map<long, AlLooper *> looperMap; std::mutex mtx;};

AlLooper

AlLooper主要有prepare、myLooper和loop三個(gè)靜態(tài)函數(shù)。prepare用于為當(dāng)前線程準(zhǔn)備一個(gè)AlLooper,因?yàn)槲覀円?guī)定同一個(gè)線程只能擁有一個(gè)AlLooper對(duì)象,如果嘗試在一個(gè)線程重復(fù)調(diào)用該函數(shù)函數(shù)將引發(fā)異常。myLooper用于獲取當(dāng)前線程的AlLooper,如果在該函數(shù)調(diào)用之前沒有調(diào)用過prepare將會(huì)獲得一個(gè)空指針。loop是AlLooper的核心函數(shù),調(diào)用該函數(shù)后線程將進(jìn)入死循環(huán),AlLooper會(huì)依次從消息隊(duì)列頭部取出AlMessage進(jìn)行消費(fèi)。前面提到AlMessage有一個(gè)名為target的成員變量,這個(gè)變量是一個(gè)AlHandler對(duì)象,所以這里直接調(diào)用AlHandler::dispatchMessage函數(shù)把消息回傳,由AlHandler進(jìn)行處理。sendMessage函數(shù)則用于在消息隊(duì)列尾部插入一條消息。

class AlLooper : public Object {public: /** * 為線程準(zhǔn)備一個(gè)Looper,如果線程已經(jīng)存在Looper,則報(bào)錯(cuò) */ static void prepare() { AlLooper *looper = AlLooperManager::getInstance()->create(Thread::currentThreadId()); assert(nullptr != looper); } /** * 獲取當(dāng)前線程的Looper * @return 前線程的Looper */ static AlLooper *myLooper() { AlLooper *looper = AlLooperManager::getInstance()->get(Thread::currentThreadId()); assert(nullptr != looper); return looper; } static void exit(); /** * 循環(huán)消費(fèi)消息 */ static void loop() { myLooper()->_loop(); } void _loop() { for (;;) { AlMessage *msg = queue.take(); if (msg) { if (msg->target) { msg->target->dispatchMessage(msg); } delete msg; } queue.pop(); } } void sendMessage(AlMessage *msg) { queue.offer(msg); }private: AlLooper(); AlLooper(AlLooper &e) : Object() {} ~AlLooper();private: AlMessageQueue queue;};

AlMessageQueue和AlMessage

AlMessage比較簡(jiǎn)單,主要包含幾個(gè)public的成員變量,用于區(qū)分消息類型以及附帶一些信息。AlMessageQueue則是一個(gè)阻塞隊(duì)列,當(dāng)嘗試從一個(gè)空隊(duì)列獲取AlMessage時(shí)將會(huì)造成線程阻塞,如果其它線程向空隊(duì)列新增一個(gè)AlMessage對(duì)象將會(huì)喚醒阻塞的線程。這是驅(qū)動(dòng)消息循環(huán)消費(fèi)的重要一環(huán)。

class AlMessage {public: int32_t what = 0; int32_t arg1 = 0; int64_t arg2 = 0; Object *obj = nullptr;}class AlMessageQueue : public Object {public: AlMessageQueue() { pthread_mutex_init(&mutex, nullptr); pthread_cond_init(&cond, nullptr); } virtual ~AlMessageQueue() { pthread_mutex_lock(&mutex); invalid = true; pthread_mutex_unlock(&mutex); clear(); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); } void offer(AlMessage *msg) { pthread_mutex_lock(&mutex); if (invalid) { pthread_mutex_unlock(&mutex); return; } queue.push_back(msg); pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex); } AlMessage *take() { pthread_mutex_lock(&mutex); if (invalid) { pthread_mutex_unlock(&mutex); return nullptr; } if (size() <= 0) { if (0 != pthread_cond_wait(&cond, &mutex)) { pthread_mutex_unlock(&mutex); return nullptr; } } if (queue.empty()) { pthread_mutex_unlock(&mutex); return nullptr; } AlMessage *e = queue.front(); queue.pop_front(); pthread_mutex_unlock(&mutex); return e; } int size(); void clear();private: pthread_mutex_t mutex; pthread_cond_t cond; std::list<AlMessage *> queue; bool invalid = false;};

AlHandlerThread

AlLooper準(zhǔn)備好后就可以在線程中使用了,這里我們把線程和AlLooper封裝到一起方便使用。AlHandlerThread會(huì)在內(nèi)部開啟一個(gè)線程,該線程會(huì)調(diào)用run函數(shù),在線程開始運(yùn)行后依次調(diào)用AlLooper的prepare和loop函數(shù)即可進(jìn)入消息消費(fèi)流程,AlLooper::exit()用于在線程結(jié)束前銷毀AlLooper對(duì)象。

class AlHandlerThread {public: AlLooper *getLooper() { return mLooper; }private: void run() { AlLooper::prepare(); mLooper = AlLooper::myLooper(); AlLooper::loop(); AlLooper::exit(); }private: std::thread mThread = thread(&AlHandlerThread::run, this); AlLooper *mLooper = nullptr;};

最后我們創(chuàng)建一個(gè)AlHandler對(duì)象,并傳入一個(gè)從AlHandlerThread獲取的AlLooper對(duì)象和一個(gè)處理回調(diào)函數(shù)Callback,便可以讓Handler機(jī)制運(yùn)行起來。由于AlLooper可以是任意一個(gè)線程的對(duì)象,所以便實(shí)現(xiàn)了跨線程的通訊。如果我們把AlMessage封裝成一個(gè)'Task',當(dāng)我們要處理一個(gè)耗時(shí)任務(wù)時(shí),把任務(wù)封裝成一個(gè)'Task'發(fā)送到Handler進(jìn)行處理,通過該方法可以輕易實(shí)現(xiàn)線程的復(fù)用,而不需要重復(fù)申請(qǐng)銷毀線程。

mThread = AlHandlerThread::create(name);mHandler = new AlHandler(mThread->getLooper(), [this](AlMessage *msg) { /// Do something.});

結(jié)語

  以上便是Android系統(tǒng)Handler機(jī)制的介紹,以及使用C++11的實(shí)現(xiàn)。上面展示的是部分核心代碼,省略了很多,實(shí)際操作還需要處理很多問題,比如線程安全、線程的退出、AlLooper的銷毀等。文章源碼出自hwvc項(xiàng)目,感興趣的讀者可以閱讀完整的AlHandlerThread源碼實(shí)現(xiàn)。

hwvc項(xiàng)目:

https://github.com/imalimin/hwvc/tree/develop

AlHandlerThread源碼:

https://github.com/imalimin/hwvc/blob/develop/src/common/thread/AlHandlerThread.cpp

到此這篇關(guān)于使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制的文章就介紹到這了,更多相關(guān)C++11 Handler機(jī)制內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Android
相關(guān)文章:
主站蜘蛛池模板: 防爆型气象站_农业气象站_校园气象站_农业四情监测系统「山东万象环境科技有限公司」 | 深圳市源和塑胶电子有限公司-首页 | 碳化硅,氮化硅,冰晶石,绢云母,氟化铝,白刚玉,棕刚玉,石墨,铝粉,铁粉,金属硅粉,金属铝粉,氧化铝粉,硅微粉,蓝晶石,红柱石,莫来石,粉煤灰,三聚磷酸钠,六偏磷酸钠,硫酸镁-皓泉新材料 | 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 | 河南砖机首页-全自动液压免烧砖机,小型砌块水泥砖机厂家[十年老厂] | 螺旋丝杆升降机-SWL蜗轮-滚珠丝杆升降机厂家-山东明泰传动机械有限公司 | 美甲贴片-指甲贴片-穿戴美甲-假指甲厂家--薇丝黛拉 | 合肥废气治理设备_安徽除尘设备_工业废气处理设备厂家-盈凯环保 合肥防火门窗/隔断_合肥防火卷帘门厂家_安徽耐火窗_良万消防设备有限公司 | 郑州大巴车出租|中巴车租赁|旅游大巴租车|包车|郑州旅游大巴车租赁有限公司 | POS机办理_个人pos机免费领取-银联pos机申请首页 | 披萨石_披萨盘_电器家电隔热绵加工定制_佛山市南海区西樵南方综合保温材料厂 | 小型数控车床-数控车床厂家-双头数控车床 | 扬子叉车厂家_升降平台_电动搬运车|堆高车-扬子仓储叉车官网 | 玉米深加工设备|玉米加工机械|玉米加工设备|玉米深加工机械-河南成立粮油机械有限公司 | 电动葫芦|环链电动葫芦-北京凌鹰名优起重葫芦 | SEO网站优化,关键词排名优化,苏州网站推广-江苏森歌网络 | 德州万泰装饰 - 万泰装饰装修设计软装家居馆| 传爱自考网_传爱自学考试网 | 黑龙江京科脑康医院-哈尔滨精神病医院哪家好_哈尔滨精神科医院排名_黑龙江精神心理病专科医院 | 澳洁干洗店加盟-洗衣店干洗连锁「澳洁干洗免费一对一贴心服务」 干洗加盟网-洗衣店品牌排行-干洗设备价格-干洗连锁加盟指南 | 底部填充胶_电子封装胶_芯片封装胶_芯片底部填充胶厂家-东莞汉思新材料 | 温室大棚建设|水肥一体化|物联网系统 | 济南铝方通-济南铝方通价格-济南方通厂家-山东鲁方通建材有限公司 | 恒温槽_恒温水槽_恒温水浴槽-上海方瑞仪器有限公司 | 不发火防静电金属骨料_无机磨石_水泥自流平_修补砂浆厂家「圣威特」 | 破碎机_上海破碎机_破碎机设备_破碎机厂家-上海山卓重工机械有限公司 | 电子海图系统-电梯检验系统-智慧供热系统开发-商品房预售资金监管系统 | 贵州科比特-防雷公司厂家提供贵州防雷工程,防雷检测,防雷接地,防雷设备价格,防雷产品报价服务-贵州防雷检测公司 | 云南外加剂,云南速凝剂,云南外加剂代加工-普洱澜湄新材料科技有限公司 | 南京泽朗生物科技有限公司-液体饮料代加工_果汁饮料代加工_固体饮料代加工 | 超细粉碎机|超微气流磨|气流分级机|粉体改性设备|超微粉碎设备-山东埃尔派粉碎机厂家 | 精密五金冲压件_深圳五金冲压厂_钣金加工厂_五金模具加工-诚瑞丰科技股份有限公司 | 100_150_200_250_300_350_400公斤压力空气压缩机-舰艇航天配套厂家 | 苏州伊诺尔拆除公司_专业酒店厂房拆除_商场学校拆除_办公楼房屋拆除_家工装拆除拆旧 | 刘秘书_你身边专业的工作范文写作小秘书| 马尔表面粗糙度仪-MAHR-T500Hommel-Mitutoyo粗糙度仪-笃挚仪器 | 硫酸钡厂家_高光沉淀硫酸钡价格-河南钡丰化工有限公司 | 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 欧必特空气能-商用空气能热水工程,空气能热水器,超低温空气源热泵生产厂家-湖南欧必特空气能公司 | 砂尘试验箱_淋雨试验房_冰水冲击试验箱_IPX9K淋雨试验箱_广州岳信试验设备有限公司 | 天津仓库出租网-天津电商仓库-天津云仓一件代发-【博程云仓】 |