最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2020年04月15日 14:14:32   作者:阿利民  
這篇文章主要介紹了使用C++11實(shí)現(xiàn)Android系統(tǒng)的Handler機(jī)制,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

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

線程作為系統(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)。

實(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)是一致的。

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)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • win10+VS2017+Cuda10.0環(huán)境配置詳解

    win10+VS2017+Cuda10.0環(huán)境配置詳解

    這篇文章主要介紹了win10+VS2017+Cuda10.0環(huán)境配置詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • C++面試基礎(chǔ)之static關(guān)鍵字詳解

    C++面試基礎(chǔ)之static關(guān)鍵字詳解

    這篇文章主要給大家介紹了關(guān)于C++面試基礎(chǔ)之static關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • 詳解C++的反調(diào)試技術(shù)與繞過手法

    詳解C++的反調(diào)試技術(shù)與繞過手法

    反調(diào)試技術(shù),惡意代碼會(huì)用它識(shí)別自身是否被調(diào)試,或者讓調(diào)試器失效,給反病毒工程師們制造麻煩,拉長(zhǎng)提取特征碼的時(shí)間線,本章將具體總結(jié)常見的反調(diào)試基礎(chǔ)的實(shí)現(xiàn)原理以及如何過掉這些反調(diào)試手段,從而讓我們能夠繼續(xù)分析惡意代碼
    2021-06-06
  • C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表)

    C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • OpenCV實(shí)現(xiàn)區(qū)域分割和區(qū)域生長(zhǎng)

    OpenCV實(shí)現(xiàn)區(qū)域分割和區(qū)域生長(zhǎng)

    區(qū)域分割是圖像處理中一個(gè)重要的任務(wù),本文主要介紹了OpenCV實(shí)現(xiàn)區(qū)域分割和區(qū)域生長(zhǎng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02
  • c++中#include &lt;&gt;與#include""的區(qū)別詳細(xì)解析

    c++中#include &lt;&gt;與#include""的區(qū)別詳細(xì)解析

    <>先去系統(tǒng)目錄中找頭文件,如果沒有在到當(dāng)前目錄下找。所以像標(biāo)準(zhǔn)的頭文件 stdio.h、stdlib.h等用這個(gè)方法
    2013-10-10
  • Cocos2d-x中實(shí)現(xiàn)彈出對(duì)話框示例

    Cocos2d-x中實(shí)現(xiàn)彈出對(duì)話框示例

    這篇文章主要介紹了Cocos2d-x中實(shí)現(xiàn)彈出對(duì)話框示例,注意本文代碼中的注釋,本文同時(shí)給出了效果圖,需要的朋友可以參考下
    2014-09-09
  • 一篇文章帶你了解C語言:入門基礎(chǔ)

    一篇文章帶你了解C語言:入門基礎(chǔ)

    這篇文章主要介紹了C語言入門之基礎(chǔ)知識(shí)詳解,文中有非常詳細(xì)的C語言使用教程及相關(guān)基礎(chǔ)知識(shí),對(duì)正在學(xué)習(xí)c語言的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-08-08
  • C語言動(dòng)態(tài)開辟內(nèi)存詳解

    C語言動(dòng)態(tài)開辟內(nèi)存詳解

    這篇文章主要為大家詳細(xì)介紹了C語言動(dòng)態(tài)開辟內(nèi)存,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • C++結(jié)構(gòu)體詳解

    C++結(jié)構(gòu)體詳解

    這篇文章主要介紹了C++ 結(jié)構(gòu)體與共用體的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下,希望能夠給你帶來幫助
    2021-09-09

最新評(píng)論

新营市| 休宁县| 嵊泗县| 台东县| 茂名市| 浦江县| 独山县| 临颍县| 崇仁县| 济源市| 新邵县| 泰顺县| 禄劝| 泾源县| 射阳县| 陆河县| 蒙城县| 三原县| 东山县| 绥滨县| 揭西县| 得荣县| 灵寿县| 扶沟县| 太原市| 富顺县| 高雄市| 澜沧| 安溪县| 五华县| 兴海县| 集安市| 汤原县| 增城市| 新乡县| 专栏| 科尔| 河南省| 全州县| 娄底市| 井研县|