EventBus源码分析_刘永雷(雷惊风)
libevent源码深度剖析十三libevent信号处理注意点

libevent源码深度剖析十三libevent信号处理注意点系列目录(1)libevent源码深度剖析一序(2)libevent源码深度剖析二 Reactor模式(3)libevent源码深度剖析三 libevent基本使用场景和事件流程(4)libevent源码深度剖析四 libevent源代码文件组织(5)libevent源码深度剖析五 libevent的核心:事件event(6)libevent源码深度剖析六初见事件处理框架(7)libevent源码深度剖析七事件主循环(8)libevent源码深度剖析八集成信号处理(9)libevent源码深度剖析九集成定时器事件(10)libevent源码深度剖析十支持I/O多路复用技术(11)libevent源码深度剖析十一时间管理(12)libevent源码深度剖析十二让libevent支持多线程(13)libevent源码深度剖析十三 libevent信号处理注意点前面讲到了 libevent 实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个 libevent 实例上注册信号事件。
依然冠名追加到 libevent 系列。
以 2 个线程为例,做简单的场景分析。
1 首先是创建并初始化线程 1 的 libevent 实例 base1 ,线程 1 的 libevent 实例 base2 ;2 在 base1 上注册 SIGALRM 信号;在 base2 上注册 SIGINT 信号;3 假设当前 base1 和 base2 上都没有注册其他的事件;4 线程 1 和 2 都进入 event_base_loop 事件循环:5 假设线程 1 先进入 event_base_loop ,并设置 evsignal_base = base1 ;并等待;6 接着线程 2 也进入 event_base_loop ,并设置 evsignal_base = base2 ;并等待;于是 evsignal_base 就指向了 base2 ;7 信号 ALARM 触发,调用服务例程:1static void evsignal_handler(int sig){2 ...3 evsignal_base->sig.evsigcaught[sig]++;4 evsignal_base->sig.evsignal_caught = 1;5 /* Wake up our notification mechanism */6 send(evsignal_base->sig.ev_signal_pair[0], 'a', 1, 0);7 ...8}于是 base2 得到通知 ALARM 信号发生了,而实际上 ALARM 是注册在 base1 上的, base2 上的 ALARM 注册 event 是空的,于是处理函数将不能得到调用;因此在 libevent 中,如果需要处理信号,只能将信号注册到一个 libevent 实例上。
知识共享-五子棋java实现源代码(雷惊风)

经典的五子棋java程序(源带码)直接复制粘贴importjava.awt.*;importjava.awt.event.*;importjava.applet.Applet;importjava.awt.Color;publicclassenzitextends Applet implements ActionListener,MouseListener,MouseMotionListener,ItemListener{intcolor_Qizi=0;//旗子的颜色标识0:白子1:黑子intintGame_Start=0;//游戏开始标志0未开始1游戏中intintGame_Body[][]=newint[16][16]; //设置棋盘棋子状态0 无子1 白子2 黑子Button b1=new Button("游戏开始");Button b2=new Button("重置游戏");Label lblWin=new Label(" ");Checkbox ckbHB[]=new Checkbox[2];CheckboxGroupckgHB=new CheckboxGroup();publicvoidinit(){setLayout(null);addMouseListener(this);add(b1);b1.setBounds(330,50,80,30);b1.addActionListener(this);add(b2);b2.setBounds(330,90,80,30);b2.addActionListener(this);ckbHB[0]=new Checkbox("白子先",ckgHB,false);ckbHB[0].setBounds(320,20,60,30);ckbHB[1]=new Checkbox("黑子先",ckgHB,false);ckbHB[1].setBounds(380,20,60,30);add(ckbHB[0]);add(ckbHB[1]);ckbHB[0].addItemListener(this);ckbHB[1].addItemListener(this);add(lblWin);lblWin.setBounds(330,130,80,30);Game_start_csh();}publicvoiditemStateChanged(ItemEvent e){if (ckbHB[0].getState()) //选择黑子先还是白子先{color_Qizi=0;}else{color_Qizi=1;}}publicvoidactionPerformed(ActionEvent e){Graphics g=getGraphics();if (e.getSource()==b1){Game_start();}else{Game_re();}}publicvoidmousePressed(MouseEvent e){}publicvoidmouseClicked(MouseEvent e){Graphics g=getGraphics();int x1,y1;x1=e.getX();y1=e.getY();if (e.getX()<20 || e.getX()>300 || e.getY()<20 || e.getY()>300) {return;}if (x1%20>10){x1+=20;}if(y1%20>10){y1+=20;}x1=x1/20*20;y1=y1/20*20;set_Qizi(x1,y1);}publicvoidmouseEntered(MouseEvent e){}publicvoidmouseExited(MouseEvent e){}publicvoidmouseReleased(MouseEvent e){}publicvoidmouseDragged(MouseEvent e){}publicvoidmouseMoved(MouseEvent e){}publicvoid paint(Graphics g){draw_qipan(g);}publicvoid set_Qizi(intx,int y) //落子{if (intGame_Start==0) //判断游戏未开始{return;}if (intGame_Body[x/20][y/20]!=0){return;}Graphics g=getGraphics();if (color_Qizi==1)//判断黑子还是白子{g.setColor(Color.black);color_Qizi=0;}else{g.setColor(Color.white);color_Qizi=1;}g.fillOval(x-10,y-10,20,20);intGame_Body[x/20][y/20]=color_Qizi+1;if (Game_win_1(x/20,y/20)) //判断输赢{lblWin.setText(Get_qizi_color(color_Qizi)+"赢了!"); intGame_Start=0;}if (Game_win_2(x/20,y/20)) //判断输赢{lblWin.setText(Get_qizi_color(color_Qizi)+"赢了!"); intGame_Start=0;}if (Game_win_3(x/20,y/20)) //判断输赢{lblWin.setText(Get_qizi_color(color_Qizi)+"赢了!"); intGame_Start=0;}if (Game_win_4(x/20,y/20)) //判断输赢{lblWin.setText(Get_qizi_color(color_Qizi)+"赢了!"); intGame_Start=0;}}public String Get_qizi_color(int x){if (x==0){return"黑子";}else{return"白子";}}publicvoid draw_qipan(Graphics G) //画棋盘15*15{G.setColor(Color.lightGray);G.fill3DRect(10,10,300,300,true);G.setColor(Color.black);for(inti=1;i<16;i++){G.drawLine(20,20*i,300,20*i);G.drawLine(20*i,20,20*i,300);}}publicvoid Game_start() //游戏开始{intGame_Start=1;Game_btn_enable(false);b2.setEnabled(true);}publicvoid Game_start_csh() //游戏开始初始化{intGame_Start=0;Game_btn_enable(true);b2.setEnabled(false);ckbHB[0].setState(true);for (inti=0;i<16 ;i++ ){for (int j=0;j<16 ;j++ ){intGame_Body[j]=0;}}lblWin.setText("");}publicvoid Game_re() //游戏重新开始{repaint();Game_start_csh();}publicvoid Game_btn_enable(boolean e) //设置组件状态{b1.setEnabled(e);b2.setEnabled(e);ckbHB[0].setEnabled(e);ckbHB[1].setEnabled(e);}publicboolean Game_win_1(intx,int y) //判断输赢横{int x1,y1,t=1;x1=x;y1=y;for (inti=1;i<5 ;i++ ){if (x1>15){break;}if (intGame_Body[x1+i][y1]==intGame_Body[x][y]) {t+=1;}else{break;}}for (inti=1;i<5 ;i++ ){if (x1<1){break;}if(intGame_Body[x1-i][y1]==intGame_Body[x][y]) {t+=1;}else{break;}}if (t>4){returntrue;}else{returnfalse;}}publicboolean Game_win_2(intx,int y) //判断输赢竖{int x1,y1,t=1;x1=x;y1=y;for (inti=1;i<5 ;i++ ){if (x1>15){break;}if (intGame_Body[x1][y1+i]==intGame_Body[x][y]){t+=1;}else{break;}}for (inti=1;i<5 ;i++ ){if (x1<1){break;}if(intGame_Body[x1][y1-i]==intGame_Body[x][y]) {t+=1;}else{break;}}if (t>4){returntrue;}else{returnfalse;}}publicboolean Game_win_3(intx,int y) //判断输赢左斜{int x1,y1,t=1;x1=x;y1=y;for (inti=1;i<5 ;i++ ){if (x1>15){break;}if (intGame_Body[x1+i][y1-i]==intGame_Body[x][y]) {t+=1;}else{break;}}for (inti=1;i<5 ;i++ ){if (x1<1){break;}if(intGame_Body[x1-i][y1+i]==intGame_Body[x][y]) {t+=1;}else{break;}}if (t>4){returntrue;}else{returnfalse;}}publicboolean Game_win_4(intx,int y) //判断输赢左斜{int x1,y1,t=1;x1=x;y1=y;for (inti=1;i<5 ;i++ ){if (x1>15){break;}if (intGame_Body[x1+i][y1+i]==intGame_Body[x][y]) {t+=1;}else{break;}}for (inti=1;i<5 ;i++ ){if (x1<1){break;}if(intGame_Body[x1-i][y1-i]==intGame_Body[x][y]) {t+=1;}else{break;}}if (t>4){returntrue;}else{returnfalse;}}}。
asynceventbus的优雅写法

一、介绍asynceventbusasynceventbus是一个事件总线库,用于在不同组件之间进行通信。
它基于Google Guava的EventBus,提供了异步事件发布和订阅的功能。
asynceventbus可以简化组件之间的通信,提高系统的可扩展性。
二、asynceventbus的用法1. 引入asynceventbus库需要在项目的build.gradle文件中引入asynceventbus库的依赖。
2. 创建事件类接下来,需要创建事件类。
事件类是一个普通的Java类,用于封装事件的数据。
3. 创建订阅者需要创建订阅者。
订阅者是一个普通的Java类,用于订阅事件并处理事件的逻辑。
4. 注册订阅者在订阅者类中,需要使用Subscribe注解标记处理事件的方法。
需要在订阅者类的初始化过程中,调用asynceventbus的注册方法,将订阅者注册到事件总线中。
5. 发布事件在需要发布事件的地方,使用asynceventbus的post方法发布事件。
事件总线会自动将事件分发给所有订阅者,并在它们的处理方法中执行对应的逻辑。
三、asynceventbus的优雅写法1. 使用合适的线程池在创建asynceventbus实例时,可以指定一个线程池。
这样可以控制事件处理的线程池,避免事件处理逻辑阻塞主线程。
2. 使用异步事件处理在订阅者处理事件的方法中,可以使用AllowConcurrentEvents注解标记,允许多个事件处理逻辑并行执行。
这样可以提升系统的性能。
3. 分发事件的策略asynceventbus提供了多种分发事件的策略,如按照订阅者的优先级顺序执行、按照事件的优先级顺序执行等。
根据实际情况选择合适的策略,可以优化事件的处理顺序。
4. 异常处理在订阅者处理事件的方法中,需要注意异常处理。
可以使用try-catch 块捕获异常,并根据实际情况进行处理,以保证系统的稳定性。
5. 使用适当的线程模型在创建asynceventbus实例时,可以选择适当的线程模型。
libevent源码分析event_base_dispatch,event_base_lo。。。

libevent源码分析event_base_dispatch,event_base_lo。
接⼝:event_base_dispatch/**Event dispatching loop 事件分配循环This loop will run the event base until either there are no more pending oractive, or until something calls event_base_loopbreak() orevent_base_loopexit().这个循环将会运⾏event base,知道没有等待的或者活动的事件,或者其它的调⽤了event_base_loopbreak()或event_base_loopexit().@param base the event_base structure returned by event_base_new() orevent_base_new_with_config() event_base_new() 或者 event_base_new_with_config() 返回的event_base对象@return 0 if successful, -1 if an error occurred, or 1 if we exited becauseno events were pending or active. 成功返回0,错误返回-1,或者1(当没有等待的或者活动事件时退出,会返回1)@see event_base_loop()*/EVENT2_EXPORT_SYMBOLint event_base_dispatch(struct event_base *base);intevent_base_dispatch(struct event_base *event_base){return (event_base_loop(event_base, 0));}跟踪event_base_loop接⼝/**Wait for events to become active, and run their callbacks.等待events 变成活动的,并运⾏对应的回调函数。
eventbus 核心工作原理

eventbus 核心工作原理EventBus是一种用于组件之间通信的开源库,它采用了发布-订阅模式,用于解耦事件的发送者和接收者。
在本文中,我们将深入探讨EventBus的核心工作原理。
EventBus的核心工作原理可以概括为以下几个步骤:1. 注册事件订阅者:在使用EventBus之前,需要首先注册事件订阅者。
事件订阅者是指希望接收特定类型事件的组件。
通过在订阅者中定义对应的事件处理方法,并使用EventBus的register()方法进行注册,订阅者就可以开始接收事件了。
2. 发布事件:当某个组件需要发送事件时,它可以使用EventBus 的post()方法发布事件。
事件可以是任意类型的对象,不同组件之间可以通过事件来传递数据或通知其他组件进行相应的操作。
3. 事件分发:当事件被发布后,EventBus会根据事件类型和订阅者的注册信息,将事件分发给对应的订阅者。
EventBus会根据订阅者的事件处理方法的参数类型,将事件发送给能够处理该类型事件的订阅者。
4. 事件处理:当订阅者接收到事件后,EventBus会自动调用订阅者中对应的事件处理方法。
订阅者可以通过事件处理方法对接收到的事件进行处理,例如更新UI界面、执行特定的逻辑操作等。
5. 取消注册:当不再需要接收事件时,订阅者可以调用EventBus 的unregister()方法取消注册。
取消注册后,订阅者将不再接收任何事件。
EventBus的核心工作原理可以简单描述为:事件订阅者通过注册的方式告诉EventBus自己对哪些事件感兴趣,当事件被发布时,EventBus会将事件分发给对应的订阅者,并调用其事件处理方法。
EventBus的核心工作原理具有以下特点:1. 解耦性:EventBus通过发布-订阅模式实现了组件之间的解耦。
发送者和接收者之间不需要直接引用对方,只需要通过事件进行通信,降低了组件之间的依赖性。
2. 灵活性:EventBus允许多个订阅者同时订阅同一类型的事件。
扫雷游戏的程序设计及代码示例

扫雷游戏的程序设计及代码示例前言:扫雷游戏是一款经典的单人益智游戏,玩家需要根据数字提示,揭开地图上隐藏的地雷,同时避免触雷。
本文将讨论扫雷游戏的程序设计思路以及提供一个简单的代码示例。
一、程序设计思路1. 游戏界面设计:扫雷游戏的界面通常包含一个方格矩阵和一些按键/菜单选项。
方格矩阵用于显示地图的状态,每个方格可以是隐藏的、揭开的、插上旗帜、标有数字或地雷等状态。
2. 游戏逻辑设计:扫雷游戏逻辑包括生成地雷布局、计算数字提示及判断游戏胜负等。
在游戏开始时,需要根据设定的难度级别随机生成地雷布局,将地雷随机分布在方格矩阵中的某些位置。
数字提示根据地雷周围的方格中地雷的数量计算得出。
游戏胜利的条件是所有非地雷方格都被揭开。
3. 用户交互设计:扫雷游戏需要与用户进行交互,比如根据用户的点击操作揭开方格、插上旗帜并标记地雷、显示计时等功能。
用户输入的坐标和操作将触发相应的逻辑判断和更新。
二、代码示例以下是一个用Python语言实现的简单扫雷游戏代码示例,供参考:```pythonimport randomdef generate_board(size, num_mines):# 生成地雷布局board = [[' ' for _ in range(size)] for _ in range(size)]mines = random.sample(range(size*size), num_mines)for mine in mines:row = mine // sizecol = mine % sizeboard[row][col] = '*'return boarddef calculate_hints(board):# 计算数字提示size = len(board)for row in range(size):for col in range(size):if board[row][col] == ' ':count = 0for i in range(max(0, row-1), min(row+2, size)): for j in range(max(0, col-1), min(col+2, size)): if board[i][j] == '*':count += 1if count > 0:board[row][col] = str(count)def reveal_square(board, row, col):# 揭开方格if board[row][col] == '*':return False # 触雷elif board[row][col] == ' ':size = len(board)queue = [(row, col)]while queue:r, c = queue.pop(0)if board[r][c] == ' ':board[r][c] = '-'for i in range(max(0, r-1), min(r+2, size)):for j in range(max(0, c-1), min(c+2, size)): if board[i][j] != '-':queue.append((i, j))elif board[r][c].isdigit():board[r][c] = board[r][c]return Truedef print_board(board, show_mines=False):# 打印游戏界面size = len(board)print('-'*(4*size+1))for row in range(size):for col in range(size):if board[row][col] == '*' and not show_mines: print(' #', end='')else:print(' ' + board[row][col], end='')print(' ')print('-'*(4*size+1))def play_game(size, num_mines):# 游戏主体逻辑board = generate_board(size, num_mines)calculate_hints(board)print_board(board)while True:row = int(input('请输入要翻开的方格行号:')) - 1 col = int(input('请输入要翻开的方格列号:')) - 1 if not (0 <= row < size and 0 <= col < size):print('输入无效,请重新输入!')continueif not reveal_square(board, row, col):print('触雷!游戏结束!')print_board(board, show_mines=True)breakprint_board(board)# 主函数if __name__ == '__main__':print('欢迎来到扫雷游戏!')size = int(input('请输入地图大小:'))num_mines = int(input('请输入地雷数量:'))play_game(size, num_mines)```三、总结以上是一个简单的扫雷游戏代码示例,通过实现游戏界面设计、游戏逻辑设计和用户交互设计,实现了基本的扫雷功能。
libevent源码深度剖析

libevent源码深度剖析第⼀章1,前⾔Libevent是⼀个轻量级的开源⾼性能⽹络库,使⽤者众多,研究者更甚,相关⽂章也不少。
写这⼀系列⽂章的⽤意在于,⼀则分享⼼得;⼆则对libevent代码和设计思想做系统的、更深层次的分析,写出来,也可供后来者参考。
附带⼀句:Libevent是⽤c语⾔编写的(MS⼤⽜们都偏爱c语⾔哪),⽽且⼏乎是⽆处不函数指针,学习其源代码也需要相当的c语⾔基础。
2,libevent简介上来当然要先夸奖啦,Libevent 有⼏个显著的亮点:=> 事件驱动(event-driven),⾼性能;=> 轻量级,专注于⽹络,不如ACE那么臃肿庞⼤;=> 源代码相当精炼、易读;=> 跨平台,⽀持Windows、Linux、*BSD和Mac Os;=> ⽀持多种I/O多路复⽤技术, epoll、poll、dev/poll、select和kqueue等;=> ⽀持I/O,定时器和信号等事件;=> 注册事件优先级;Libevent已经被⼴泛的应⽤,作为底层的⽹络库;⽐如memcached、Vomit、Nylon、Netchat等等。
Libevent当前的最新稳定版是1.4.13;这也是本⽂参照的版本。
3,学习的好处学习libevent有助于提升程序设计功⼒,除了⽹络程序设计⽅⾯外,Libevent的代码⾥有很多有⽤的设计技巧和基础数据结构,⽐如信息隐藏、函数指针、c语⾔的多态⽀持、链表和堆等等,都有助于提升⾃⾝的程序功⼒。
程序设计不⽌要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。
只对libevent本⾝的框架⼤概了解,那或许仅仅是⼀知半解,不深⼊代码分析,就难以了解其设计的精巧之处,也就难以为⾃⼰所⽤。
事实上Libevent本⾝就是⼀个典型的Reactor模型,理解Reactor模式是理解libevent的基⽯;因此下⼀节将介绍典型的事件驱动设计模式——Reactor模式。
兄弟连区块链入门教程以太坊源码分析event源码分析

兄弟连区块链入门教程以太坊源码分析event源码分析兄弟连区块链入门教程以太坊源码分析event源码分析,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。
但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。
event包实现了同一个进程内部的事件发布和订阅模式。
## event.go目前这部分代码被标记为Deprecated,告知用户使用Feed这个对象。
不过在代码中任然有使用。
而且这部分的代码也不多。
就简单介绍一下。
数据结构TypeMux是主要的使用。
subm记录了所有的订阅者。
可以看到每中类型都可以有很多的订阅者。
// TypeMuxEvent is a time-tagged notification pushed to subscribers.type TypeMuxEvent struct {Time time.TimeData interface{}}// A TypeMux dispatches events to registered receivers. Receivers can be// registered to handle events of certain type. Any operation// called after mux is stopped will return ErrMuxClosed.//// The zero value is ready to use.//// Deprecated: use Feedtype TypeMux struct {mutex sync.RWMutexsubm map[reflect.Type][]*TypeMuxSubscriptionstopped bool}创建一个订阅,可以同时订阅多种类型。
// Subscribe creates a subscription for events of the given types. The// subscription's channel is closed when it is unsubscribed// or the mux is closed.func (mux *TypeMux) Subscribe(types ...interface{}) *TypeMuxSubscription {sub := newsub(mux)mux.mutex.Lock()defer mux.mutex.Unlock()if mux.stopped {// set the status to closed so that calling Unsubscribe after this// call will short circuit.sub.closed = trueclose(sub.postC)} else {if mux.subm == nil {mux.subm = make(map[reflect.Type][]*TypeMuxSubscription)}for _, t := range types {rtyp := reflect.TypeOf(t)oldsubs := mux.subm[rtyp]if find(oldsubs, sub) != -1 {panic(fmt.Sprintf("event: duplicate type %s in Subscribe", rtyp))}subs := make([]*TypeMuxSubscription, len(oldsubs)+1)copy(subs, oldsubs)subs[len(oldsubs)] = submux.subm[rtyp] = subs}}return sub}// TypeMuxSubscription is a subscription established through TypeMux.type TypeMuxSubscription struct {mux *TypeMuxcreated time.TimecloseMu sync.Mutexclosing chan struct{}closed bool// these two are the same channel. they are stored separately so// postC can be set to nil without affecting the return value of// Chan.postMu sync.RWMutex// readC 和postC 其实是同一个channel。
Libevent源码分析—event_add()

Libevent源码分析—event_add()接下来就是将已经初始化的event注册到libevent的事件链表上,通过event_add()来实现,源码位于event.c中。
event_add()这个函数主要完成了下⾯⼏件事:1.将event注册到event_base的I/O多路复⽤要监听的事件中2.将event注册到event_base的已注册事件链表中3.如果传⼊了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的⼩根堆中;如果没有传⼊超时时间,则不会添加到⼩根堆中。
只有步骤1成功,才会执⾏步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。
从中还可以看到,将event添加到已注册事件链表、添加到⼩根堆、从活跃事件链表移除、从⼩根堆中移除,都是通过两个函数完成的:event_queue_insert()、event_queue_remove()intevent_add(struct event *ev, const struct timeval *tv){struct event_base *base = ev->ev_base; //event所属的event_baseconst struct eventop *evsel = base->evsel; //event_base的I/O多路复⽤机制void *evbase = base->evbase; //event_base的I/O多路复⽤机制int res = 0;//DEBUG log.hevent_debug(("event_add: event: %p, %s%s%scall %p",ev,ev->ev_events & EV_READ ? "EV_READ " : "",ev->ev_events & EV_WRITE ? "EV_WRITE " : "",tv ? "EV_TIMEOUT " : "",ev->ev_callback));assert(!(ev->ev_flags & ~EVLIST_ALL));/** prepare for timeout insertion further below, if we get a* failure on any step, we should not change any state.*///如果传⼊了超时时间并且event不再time⼩根堆上,则在⼩根堆上预留⼀个位置//以保证如果后⾯有步骤失败,不会改变初始状态,保证是个原⼦操作if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {if (min_heap_reserve(&base->timeheap, //min_heap.h1 + min_heap_size(&base->timeheap)) == -1)return (-1); /* ENOMEM == errno */}//如果event不在已注册链表或活跃链表中,//则调⽤evsel->add()注册event事件到I/O多路复⽤监听的事件上if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {res = evsel->add(evbase, ev); //将event注册到监听事件上//注册监听事件成功,则将event注册到已注册事件链表上if (res != -1)event_queue_insert(base, ev, EVLIST_INSERTED); //插⼊}/** we should change the timout state only if the previous event* addition succeeded.*///前⾯操作都成功情况下,才能执⾏下⾯步骤//改变超时状态if (res != -1 && tv != NULL) {struct timeval now;/** we already reserved memory above for the case where we* are not replacing an exisiting timeout.*///EVLIST_TIMEOUT表明event已在定时器堆中//则删除旧的定时器if (ev->ev_flags & EVLIST_TIMEOUT)event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除/* Check if it is active due to a timeout. Rescheduling* this timeout before the callback can be executed* removes it from the active list. *///如果事件是由于超时⽽变成活跃事件//则从活跃事件链表中删除if ((ev->ev_flags & EVLIST_ACTIVE) &&(ev->ev_res & EV_TIMEOUT)) {/* See if we are just active executing thisif (ev->ev_ncalls && ev->ev_pncalls) {/* Abort loop */*ev->ev_pncalls = 0; //调⽤次数清0}//从活跃事件链表移除event_queue_remove(base, ev, EVLIST_ACTIVE); //移除}gettime(base, &now);evutil_timeradd(&now, tv, &ev->ev_timeout); //为event添加超时时间event_debug(("event_add: timeout in %ld seconds, call %p",tv->tv_sec, ev->ev_callback));//将event插⼊到⼩根堆中event_queue_insert(base, ev, EVLIST_TIMEOUT); //插⼊}return (res);}event_queue_insert()该函数根据不同的输⼊队列,即不同的事件,在不同的队列中插⼊,并增加相应的事件计数,更新event状态;EVLIST_INSERTED:在已注册事件链表event_base.eventqueue插⼊EVLIST_ACTIVE:根据event优先级,在活跃事件链表event_base.activequeues[event.ev_pri]插⼊EVLIST_TIMEOUT:在⼩根堆event_base.timeheap中插⼊voidevent_queue_insert(struct event_base *base, struct event *ev, int queue){//如果event已经在活跃链表中,则返回;否则,出错if (ev->ev_flags & queue) {/* Double insertion is possible for active events */if (queue & EVLIST_ACTIVE)return;event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,ev, ev->ev_fd, queue);}if (~ev->ev_flags & EVLIST_INTERNAL)base->event_count++; //增加注册事件数ev->ev_flags |= queue; //改变event状态switch (queue) { //根据不同的输⼊参数队列,选择在不同的事件集合中插⼊case EVLIST_INSERTED: //I/O或Signal事件TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); //在已注册事件链表插⼊break;case EVLIST_ACTIVE: //活跃事件base->event_count_active++; //增加活跃事件数TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], //在活跃事件链表插⼊ev,ev_active_next);break;case EVLIST_TIMEOUT: { //定时器事件min_heap_push(&base->timeheap, ev); //在⼩根堆插⼊break;}default:event_errx(1, "%s: unknown queue %x", __func__, queue);}}event_queue_remove()和event_queue_insert()相对应,这个函数主要根据不同的输⼊参数,从不同的事件集合中删除事件。
EventBus使用及源码解析

EventBus使用及源码解析1、前言EventBus是由greenrobot开源的android事件订阅/发布轻量级框架,通过把事件发布者和接受者解耦进而简化android事件传递,其作用堪比android原有的handler、intent、broadcast,实现activity、fragment、service 以及线程之间的通信;1.1原理1.2概述2、EventBus2.1使用EventBus应用并通过demo实践:分别用主线程发送数据和接送粘性数据进行了实践,其中有两种发送方式:2.1.1主线程发送数据的使用步骤(1)导jar包或添加依赖;(2)注册广播;(3)解注册广播;(4)构建消息类;(5)发送消息;(6)接送消息;2.1.2使用粘性事件而使用粘性事件则可以先发送消息,接收消息时再进行注册;(1)构造发送消息类;(2)发送界面发送消息;(3)目标界面实现接收消息的方法(添加@Subcruibe注解);(4)注册广播;(5)解注册(增加移除所有粘性事件的方法);2.2源码解析2.2.1获取实例getDefault为一个单例方法,获取EventBus单例;public static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {defaultInstance = new EventBus();}}}return defaultInstance;}2.2.2 New EventBuspublic EventBus() {this(DEFAULT_BUILDER);}在这里有调用了另外一个构造函数完成相关属性的初始化EventBus(EventBusBuilder builder) {subscriptionsByEventType = new HashMap<>();typesBySubscriber = new HashMap<>();stickyEvents = new ConcurrentHashMap<>();mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);backgroundPoster = new BackgroundPoster(this);asyncPoster = new AsyncPoster(this);indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);logSubscriberExceptions = builder.logSubscriberExceptions;logNoSubscriberMessages = builder.logNoSubscriberMessages;sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;sendNoSubscriberEvent = builder.sendNoSubscriberEvent;throwSubscriberException = builder.throwSubscriberException;eventInheritance = builder.eventInheritance;executorService = builder.executorService;}DefaultBuilder就是一个默认的EventBusBuilder;有了EventBus实例就可以进行注册了,public void register(Object subscriber) {//得到当前注册类的class对象;Class<?> subscriberClass = subscriber.getClass();//根据Class查找当前类中订阅事件方法的集合,即使用了@Subcribe注解,有public修饰符、一个参数的方法;//SubscriberMethod类主要封装了符合条件方法的相关信息//Method对象、线程模式、事件类型、优先级、是否粘性事件等;List<SubscriberMethod> subscriberMethods =subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) {//循环遍历了订阅了事件的方法的集合,以完成注册for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}2.2.3Registeregister方法主要分成两部分:查找和注册:首先看查找部分的代码:List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { // METHOD_CACHE是一个ConcurrentHashMap,直接保存了subscriberClass和对应SubscriberMethod的集合,以提高注册效率,赋值重复查找。
eventbus详细原理

eventbus详细原理EventBus是一种通信机制,主要用于在程序内部的不同组件之间进行消息传递和事件触发。
它采用了观察者模式的思想,简化了组件之间的耦合度,提高了代码的可读性和可维护性。
EventBus的基本原理是通过一个中心事件总线来连接组件之间的通信。
每个组件可以选择订阅感兴趣的事件,同时也可以发布自己的事件。
当一个事件被发布时,EventBus会将该事件发送给所有订阅了该事件的组件,使这些组件能够处理该事件。
EventBus支持不同的事件类型,可以根据实际需求来定义事件对象。
一般而言,事件对象需要包含一些必要的信息,比如事件类型、事件数据等。
当一个事件被发布时,EventBus会遍历所有的订阅者,调用其对应的事件处理方法,并将事件对象作为参数传递给处理方法。
EventBus的事件处理方法通常使用注解来标识,以告诉EventBus该方法是一个事件处理方法。
常见的注解有@Subscribe和@Produce,分别用于订阅事件和发布事件。
当一个组件订阅了某个事件后,其对应的事件处理方法将会被自动调用。
而当一个组件发布了某个事件后,EventBus会寻找所有订阅了该事件的组件,并调用它们的事件处理方法。
EventBus还支持事件的粘性和优先级。
粘性事件是指在事件发布之前,订阅者可以先注册并接收到该事件的最后一次发布记录,以便处理可能在注册之前就已经发生的事件。
而优先级可以让订阅者按照一定的顺序接收事件,以便处理先到达的事件或者保证某个订阅者的事件处理方法先于其他订阅者执行。
总结起来,EventBus通过简化组件之间的通信方式,提供了一种方便灵活的消息传递和事件触发机制。
它的原理基于观察者模式,通过事件总线连接组件,实现组件之间的解耦和高效通信。
无论是在Android开发中还是在其他领域的应用中,EventBus都是一个非常有用的工具。
凌风引擎源码

凌风引擎源码引言凌风引擎是一款开源的游戏引擎,它提供了丰富的功能和工具,用于开发高质量的游戏。
本文将深入探讨凌风引擎的源码,包括其架构、核心功能和实现细节等方面。
架构概述凌风引擎的架构采用了模块化设计,分为核心模块、图形模块、物理模块和音频模块等多个子系统。
下面将对每个子系统进行详细介绍。
核心模块核心模块是凌风引擎的基础,负责提供游戏运行的基本功能。
它包括了游戏循环、事件处理、资源管理和场景管理等功能。
核心模块的源码结构清晰,易于理解和扩展。
图形模块图形模块用于渲染游戏场景和对象。
它支持多种渲染技术,如2D和3D渲染、光照、阴影和特效等。
图形模块的源码实现了高效的渲染算法和优化技巧,使游戏画面更加流畅和逼真。
物理模块物理模块用于模拟游戏中的物理效果,如重力、碰撞和运动等。
它采用了先进的物理引擎,能够准确地计算物体的运动和碰撞反应。
物理模块的源码结构清晰,易于集成到游戏中。
音频模块音频模块用于播放游戏中的音效和音乐。
它支持多种音频格式和效果,如立体声、回声和混音等。
音频模块的源码实现了高效的音频处理算法,使游戏的音效更加逼真和震撼。
核心功能除了以上子系统,凌风引擎还提供了许多核心功能,包括资源加载、碰撞检测、动画控制和网络通信等。
下面将对其中几个核心功能进行详细介绍。
凌风引擎的资源加载功能支持多种资源类型,如图片、音频、模型和字体等。
它提供了统一的接口和管理器,方便开发者加载和管理游戏资源。
资源加载功能的源码采用了高效的异步加载机制,能够提高游戏的加载速度和性能。
碰撞检测碰撞检测是游戏开发中常用的功能之一,凌风引擎提供了强大的碰撞检测功能。
它支持多种碰撞形状,如矩形、圆形和多边形等。
碰撞检测功能的源码实现了高效的算法和优化技巧,能够快速准确地检测游戏对象之间的碰撞。
动画控制动画控制是游戏中带有动态效果的对象的基础,凌风引擎提供了灵活易用的动画控制功能。
它支持多种动画类型,如帧动画、骨骼动画和粒子动画等。
libevent源码解析

libevent源码解析libevent是一个事件触发型的网络通信库,它主要用于实现高效、可扩展、高并发的网络通信,广泛应用于服务器程序的开发中。
libevent源码可运行于Windows、Linux等操作系统,并提供了C、C++、Python等多种语言接口,被广泛应用于各种网络通信场景。
libevent源码的主要结构及功能libevent的设计基于事件驱动的思想,实现了高效的异步非阻塞I/O模型。
它能够有效地处理大量的并发连接请求,支持多种协议、多路复用、定时器、信号处理等功能,是一个功能强大、易于扩展的网络通信库。
其源码主要包括以下几个重要的结构和功能:1. event_base:这是libevent的核心结构,他负责管理和调度所有事件,包括I/O事件、信号事件、定时器事件等。
event_base可以同时处理多个不同类型的事件,并且支持事件优先级和超时事件的处理。
libevent库中所有其他的结构都需要与event_base关联才能生效。
2. event:event是事件处理的最小单位,它代表一个被监视的文件描述符或是一个信号等。
当文件描述符有数据可读写或者信号触发时,就会触发相应的事件处理程序。
每个event都需要与一个event_base关联,以便能够得到正确的事件调度。
3. evutil:evutil是libevent的基本工具库,主要提供了跨平台的网络编程接口,如字符串操作、字符串解析、socket地址解析等。
evutil是libevent实现的基础库,所有其他高层次的实现都依赖于它。
4. bufferevent:这是一个对I/O进行封装的结构,用于处理基于缓存的I/O通信、数据包的发送和接收等功能。
它可以自动处理TCP流的拆分和合并,同时实现了读写缓冲区管理、超时和错误处理等功能。
5. timeval:这是一个时间相关的结构,主要用于管理事件的超时处理和事件的定时器操作。
libevent中事件操作的时间精度为微秒级。
eventbus 原理

eventbus 原理摘要:1.事件总线(EventBus)概念介绍2.事件总线(EventBus)的工作原理3.事件总线(EventBus)的应用场景及优势4.事件总线(EventBus)的实现方法5.事件总线(EventBus)的优缺点分析6.我国事件总线(EventBus)的发展现状与趋势正文:一、事件总线(EventBus)概念介绍事件总线(EventBus)是一种在软件系统中实现组件间解耦、高度灵活且可扩展的通信机制。
它允许组件之间异步地发布和订阅事件,从而实现松耦合的通信模式。
在实际应用中,事件总线被广泛应用于处理业务逻辑、数据变更、消息通知等场景。
二、事件总线(EventBus)的工作原理事件总线(EventBus)的工作原理可以概括为三个步骤:1.事件发布:当一个组件需要触发某个事件时,它会将事件对象发布到事件总线上。
2.事件订阅:其他组件可以订阅事件总线上的事件,当事件被发布后,订阅该事件的组件将收到通知。
3.事件处理:收到通知的组件可以根据事件对象的内容执行相应的处理逻辑。
三、事件总线(EventBus)的应用场景及优势1.应用场景:事件总线适用于需要跨系统、跨模块、跨层次通信的场景,如业务逻辑处理、数据变更通知、消息推送等。
2.优势:事件总线(EventBus)具有以下优势:- 解耦:组件之间无需直接相互依赖,降低模块间的耦合度,便于维护和扩展。
- 灵活性:支持异步发布和订阅事件,满足不同场景的通信需求。
- 扩展性:事件总线可以轻松地添加或删除事件类型和订阅者,支持动态扩展。
四、事件总线(EventBus)的实现方法事件总线的实现方法有多种,如使用消息队列、发布/订阅模式等。
以下以Java中的Google Guava库中的EventBus为例,简要介绍实现方法:1.引入依赖:在项目的pom.xml文件中添加Guava依赖。
2.创建事件类:定义事件类,继承自java.util.EventObject。
eventbus原理

eventbus原理
EventBus是一种事件总线机制,用于实现发布-订阅模式。
它通过解耦事件的发布者和订阅者,使得它们彼此不直接依赖,并且能够在运行时动态添加或移除订阅者。
EventBus的工作原理如下:
1. 定义事件:首先要定义需要发布或订阅的事件。
一个事件可以是任意的Java对象,通常是通过创建一个包含需要传递的数据的POJO类来实现。
2. 注册订阅者:在需要接收事件通知的地方,订阅者需要注册到EventBus中才能接收到相关事件。
这通常在组件的初始化阶段完成。
3. 发布事件:发布者使用EventBus将事件发布到总线上。
EventBus负责将事件分发给所有已注册的订阅者。
4. 订阅事件:订阅者定义一个处理事件的方法,然后将其注册到EventBus中以接收特定类型的事件。
当事件被发布时,EventBus会自动调用订阅者的处理方法,并且会将事件作为参数传递给方法。
5. 取消订阅:当不再需要接收特定类型的事件时,订阅者可以取消订阅。
这样,EventBus将不再将该类型的事件发送给该订阅者。
通过使用EventBus,组件之间的耦合性得到降低,事件的发
布和订阅可以在运行时动态地添加或移除,使得代码更加灵活和可扩展。
同时,EventBus还提供了多种不同的线程模型来
控制事件在不同线程之间的分发方式,以满足不同的业务需求。
java代码fireevent详解

java代码fireevent详解Java代码fireevent详解FireEvent是Java的一个核心事件框架,它基于事件观察者模式实现,为事件发布者和事件订阅者之间提供了一个可以使用的框架。
FireEvent可以帮助Java开发人员快速地实现事件监听、处理,更加准确、高效地进行数据传导。
下面将详细介绍FireEvent:1、什么是FireEvent?FireEvent是一个基于事件观察者模式(Observer Pattern)的事件发布框架,它允许应用开发人员将事件发布出去并通知相关的订阅者,从而实现事件间的解耦。
2、FireEvent的主要类FireEvent中的主要类如下:EventBus:事件总线,管理事件的注册、发布和订阅过程。
EventListener:事件监听器,用于对事件进行检测,并调用相应的处理函数。
EventHandler:事件处理器,用于实现事件的处理及响应动作。
3、FireEvent的工作流程FireEvent的工作流程如下:(1)首先,程序通过EventBus实例来注册一系列事件,每个事件都由一个字符串标识;(2)然后,EventBus会管理多个EventListener实例,每个EventListener都监听不同的事件;(3)当某个事件发生时,程序通过调用EventBus的publish()方法发布该事件,事件信息就会传到多个EventListener实例中;(4)每个EventListener都会检查自己是否关心收到的事件,如果关心,就会触发一个EventHandler,用于实现实际的事件处理操作;(5)此时,EventHandler会根据事件类型和参数来进行处理,处理完之后返回一个响应动作;(6)在完成处理后,EventBus就会将该响应动作通知EventListener,由EventListener完成具体的动作。
4、FireEvent的优缺点FireEvent的优点:能够更快、更有效的分发数据和完成事件操作;可以解耦事件发布者与事件订阅者之间的耦合;支持同步和异步模式,提高性能;支持事件组的使用,提高复用性;简化了事件监听和处理等复杂操作。
EventBus(三)源码解析带你深入理解EventBus

EventBus(三)源码解析带你深⼊理解EventBus上⼀篇带⼤家初步了解了EventBus的使⽤⽅式,详见: EventBus实战没听过你就out了,本篇博客将解析EventBus的源码,相信能够让⼤家深⼊理解该框架的实现,也能解决很多在使⽤中的疑问:为什么可以这么做?为什么这么做不好呢?1、概述⼀般使⽤EventBus的组件类,类似下⾯这种⽅式:[java]1. public class SampleComponent extends Fragment2. {3.4. @Override5. public void onCreate(Bundle savedInstanceState)6. {7. super.onCreate(savedInstanceState);8. EventBus.getDefault().register(this);9. }10.11. public void onEventMainThread(param)12. {13. }14.15. public void onEventPostThread(param)16. {17.18. }19.20. public void onEventBackgroundThread(param)21. {22.23. }24.25. public void onEventAsync(param)26. {27.28. }29.30. @Override31. public void onDestroy()32. {33. super.onDestroy();34. EventBus.getDefault().unregister(this);35. }36.37. }⼤多情况下,都会在onCreate中进⾏register,在onDestory中进⾏unregister ;看完代码⼤家或许会有⼀些疑问:1、代码中还有⼀些以onEvent开头的⽅法,这些⽅法是⼲嘛的呢?在回答这个问题之前,我有⼀个问题,你咋不问register(this)是⼲嘛的呢?其实register(this)就是去当前类,遍历所有的⽅法,找到onEvent开头的然后进⾏存储。
[EventBus源码解析]EventBus.post方法详述
![[EventBus源码解析]EventBus.post方法详述](https://img.taocdn.com/s3/m/cd990116974bcf84b9d528ea81c758f5f61f29b2.png)
[EventBus源码解析]EventBus.post⽅法详述前情概要 上⼀篇blog我们了解了EventBus中register/unregister的过程,对EventBus如何实现观察者模式有了基本的认识。
今天我们来看⼀下它是如何分发⼀个特定事件的,即post(Object event)⽅法。
本篇概述 EventBus中事件的分发与响应,post ⽅法。
post ⽅法public void post(Object event) {PostingThreadState postingState = currentPostingThreadState.get();List<Object> eventQueue = postingState.eventQueue;eventQueue.add(event);if (!postingState.isPosting) {postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();postingState.isPosting = true;if (postingState.canceled) {throw new EventBusException("Internal error. Abort state was not reset");}try {while (!eventQueue.isEmpty()) {postSingleEvent(eventQueue.remove(0), postingState);}} finally {postingState.isPosting = false;postingState.isMainThread = false;}}} postingState(分发状态)具有ThreadLocal属性,包含⼀个eventQueue,⽤来保存当前线程分发中的event,在while循环中,逐⼀调⽤ postSingleEvent(eventQueue.remove(0), postingState),清空发送队列。
eventbus源码解析

eventbus源码解析EventBus是一个开源的轻量级Android事件总线,是极其常用的一种解耦方式,基于发布-订阅模式实现,主要用来完成对象之间的消息传递,功能非常强大。
那么,本文将围绕“EventBus源码解析”展开,以揭示其神秘面纱。
1.第一步,说说事件发送和订阅。
EventBus的核心机制就是发布和订阅模型。
在EventBus系统中,事件的发送方和接收方没有直接的引用关系,完全靠反射的方式,系统可以将发送方和接收方的代码耦合度彻底割断,实现消息发布时的解耦,以及消息订阅(注册)时的解耦。
2.第二步,解析订阅方法的生成。
在源码分析中,我们应该先分析如何生成订阅方法。
EventBus通过反射机制,在订阅者的类中调用了onEvent方法并将事件对象传递给该方法。
onEvent方法中包含了可以被调用的接收事件对象的方法。
在订阅者订阅事件时,可以通过使用注解将其方法标记为能够接收事件对象的方法。
具体实现还需看EventBus类的register和unregister函数。
3.第三步,讲一下事件的发送。
在事件发送时,EventBus中的post函数调用了事件的处理函数即subscriber,通过反射机制调用了register函数,最终执行到handler的方法中,利用handler处理函数调用eventBus方法中的proessEvent(Object event,Subscription subscription)传递参数,处理事件和订阅者。
判断订阅者有哪些接收事件,有则是将eventBus.postQueue中的事件与订阅方法做匹配,当有订阅者与发布者关联时,就要比较其线程模式(通过注解运行)。
具体实现还需看EventBus类的post函数。
4.第四步,介绍EventBus的线程模式。
EventBus中有4种线程模式,分别是PostThread,MainThread,BackgroundThread和AsyncThread。
eventbus 详解

eventbus 详解1.EventBus(事件总线)是一种在软件架构中用于组件之间通信的模式。
它允许不同组件之间进行松耦合的通信,通过发布和订阅事件的方式实现信息传递。
在本文中,我们将详细探讨EventBus的原理、用法以及在实际应用中的优势。
2. EventBus 原理EventBus的核心原理是基于观察者模式。
它包含一个事件总线(Event Bus)和一组事件处理器(Event Handlers)。
当一个组件发布一个事件时,事件总线将负责将这个事件传递给所有订阅了该事件的组件的事件处理器。
这种机制实现了发布-订阅模式,让组件之间能够松散耦合,提高了系统的可维护性和可扩展性。
3. EventBus 的使用3.1. 安装和引入在许多编程语言和框架中,都有支持EventBus的库。
例如,在Android 开发中,常用的EventBus库是GreenRobot的EventBus。
安装和引入通常是通过依赖管理工具或手动下载并引入库文件完成的。
java// 在Android 项目中使用EventBus 的依赖引入implementation 'org.greenrobot:eventbus:3.2.0'3.2. 创建事件类首先,需要定义事件类,即你希望在组件之间传递的消息的数据结构。
这个类通常包含一些字段,表示事件的内容。
javapublic class MessageEvent {public String message;public MessageEvent(String message){this.message=message;}}3.3. 注册和注销事件处理器在需要接收事件的组件中,需要注册和注销事件处理器。
通常,这是在组件的生命周期中完成的,以确保只有在需要的时候才会接收到事件。
javapublic class MyActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(yout.activity_main);// 注册事件处理器EventBus.getDefault().register(this);}@Overrideprotected void onDestroy(){// 注销事件处理器EventBus.getDefault().unregister(this);super.onDestroy();}// 定义事件处理方法@Subscribe(threadMode =ThreadMode.MAIN)public void onMessageEvent(MessageEvent event){// 处理接收到的事件String message =event.message;// ...}}3.4. 发布事件在需要发布事件的地方,创建事件实例并通过EventBus发布。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
EventBus源码分析一.简单介绍。
EventBus定义:是一个发布/ 订阅的开源框架,要用于事件的发布和订阅,一般传递事件的方式主要有Handler、BroadCastReceiver、Interface 回调等,EventBus的好处主要在于代码简单,使用方便,充分了降低订阅者与发布者的耦合度,所有的事件都交由EventBus这个事件总线来管理。
二.涉及到的模块。
想通过Eventbus完成事件传递,至少要涉及3个部分,订阅者、发布者、事件,下边逐个简单介绍。
1.订阅者。
订阅一个或多个事件对象,当发布者发布对应事件后,EventBus会查找所有订阅了本事件的所有订阅者,并执行订阅者操作类中相应的OnEvent*(Object)方法,完成对应操作。
订阅方法:EventBus.getDefault().register(this);单例模式。
2.发布者。
顾名思义,就是发布某个事件的对象,当发布者完成特定任务后,发布事件,事件总线EventBus通过事件获取对应的订阅者列表,循环执行订阅者中对应的OnEvent*(Object)事件响应函数。
发布事件方法:EventBus.getDefault().post(EventOb);3.事件。
就是一个对象。
可以携带一些处理后的信息。
分为普通事件和Sticky 事件,相对于一般事件,Sticky 事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个Sticky 事件。
三.用到的方法及作用。
1.EventBus.getDefault().register(this);注册当前类到事件总线EventBus。
This参数为当前activity的上下文对象。
写在订阅者对象中。
2.EventBus.getDefault().post(new EventOB());发布一个EventOB事件到事件总线EventBus中,EventOB为发布的事件类型,也就是一个对象。
3.Public void onEvent/onEvenMainThread /BackgroundThread /Async(){};当发布者发布事件后,EventBus找到订阅者后通过订阅者的ThreadMode名称类型在相应线程执行内部代码。
ThreadMode共四种:①PostThread:直接调用订阅者的事件响应函数;②MainThread 并且发布线程就是主线程,则直接调用订阅者的事件响应函数,否则通过主线程的Handler 发送消息在主线程中处理——调用订阅者的事件响应函数;③BackgroundThread 并且发布线程是主线程,则启动异步线程去处理,否则直接直接调用订阅者的事件响应函数;♍Async ,则启动异步线程去处理——调用订阅者的事件响应函数。
4.EventBus.getDefault().unRegister(this);取消当前类订阅。
四.源码分析。
1.从订阅开始:订阅流程图public void register(Object subscriber) {register(subscriber, false, 0);}注释:以上调用三个参数注册方法subscriber为调用者acticity上下文对象;再看三参数方法:private synchronized void register(Object subscriber, boolean sticky, int priority) {List<SubscriberMethod> subscriberMethods =subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod, sticky, priority);}}注释:看参数subscriber:上下文对象;Sticky:是否粘性(当再次有新订阅者,老订阅者能收到处理信息);priority:优先级设置,优先级越高,首先执行。
subscriberMethodFinder订阅者响应函数信息存储和查找类。
ubscriberMethodFinder.findSubscriberMethods(subscriber.getClass())方法:List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {String key = subscriberClass.getName();List<SubscriberMethod> subscriberMethods;synchronized (methodCache) {subscriberMethods = methodCache.get(key);}if (subscriberMethods != null) {return subscriberMethods;}subscriberMethods = new ArrayList<SubscriberMethod>();Class<?> clazz = subscriberClass;HashSet<String> eventTypesFound = new HashSet<String>();StringBuilder methodKeyBuilder = new StringBuilder();while (clazz != null) {String name = clazz.getName();if (name.startsWith("java.") || name.startsWith("javax.") ||name.startsWith("android.")) {// Skip system classes, this just degrades performancebreak;}// Starting with EventBus 2.2 we enforced methods to be public (might changewith annotations again)Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {String methodName = method.getName();if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {int modifiers = method.getModifiers();if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length == 1) {String modifierString =methodName.substring(ON_EVENT_METHOD_NAME.length());ThreadMode threadMode;if (modifierString.length() == 0) {threadMode = ThreadMode.PostThread;} else if (modifierString.equals("MainThread")) {threadMode = ThreadMode.MainThread;} else if (modifierString.equals("BackgroundThread")) { threadMode = ThreadMode.BackgroundThread;} else if (modifierString.equals("Async")) {threadMode = ThreadMode.Async;} else {if(skipMethodVerificationForClasses.containsKey(clazz)) {continue;} else {throw new EventBusException("Illegal onEvent method, check for typos: " + method);}}Class<?> eventType = parameterTypes[0];methodKeyBuilder.setLength(0);methodKeyBuilder.append(methodName);methodKeyBuilder.append('>').append(eventType.getName());String methodKey = methodKeyBuilder.toString();if (eventTypesFound.add(methodKey)) {// Only add if not already found in a sub classsubscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));}}} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."+ methodName);}}}clazz = clazz.getSuperclass();}if (subscriberMethods.isEmpty()) {throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "+ ON_EVENT_METHOD_NAME);} else {synchronized (methodCache) {methodCache.put(key, subscriberMethods);}return subscriberMethods;}}注释:看核心部分:首先通过name去缓存中查找,存在直接返回,不存在继续往下走。