前言
EventBus框架
EventBus是一个通用的叫法,例如Google出品的Guava,Guava是一个庞大的库,EventBus只是它附带的一个小功能,因此实际项目中使用并不多。用的最多的是greenrobot/EventBus,这个库的优点是接口简洁,集成方便,但是限定了方法名,不支持注解。另一个库square/otto修改自 Guava ,用的人也不少。所以今天我们研究的目标是greenrobot的EventBus.
EventBus 简介
1、EventBus3.0.0 是最新的版本。
2、EventBus 是Android 发布/订阅事件总线,可简化 Activities, Fragments, Threads, Services 等组件间的消息传递。
3、可替代 Intent, Handler, BroadCast ,接口等传统方案,更快,代码更小,50K 左右的 jar 包,代码更优雅,彻底解耦。
github地址:https://github.com/greenrobot/EventBus
EventBus原理图
如何添加依赖
在module的build.gredle 文件中的dependencies标签中添加
compile 'org.greenrobot:eventbus:3.0.0'
例如
apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.3" defaultConfig { applicationId "com.eventbus.app" minSdkVersion 14 targetSdkVersion 24 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:24.2.1' compile 'org.greenrobot:eventbus:3.0.0' }
如何使用
注册事件
EventBus.getDefault().register( this );
取消注册
EventBus.getDefault().unregister( this );
发送数据
EventBus.getDefault().post( "我发射了");
简单小例子:使用EventBus传递简单字符串
package com.eventbus.app; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //注册 EventBus.getDefault().register( this ); findViewById( R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post( "我发射了"); } }); } /** * 自定义一个方法 hello() ,用来接收事件。 * 方法名字可以随便写 * @return */ @Subscribe(threadMode = ThreadMode.MAIN) public void hello ( String event){ /* Do something */ Toast.makeText( this , event , Toast.LENGTH_SHORT).show(); }; @Override protected void onDestroy() { super.onDestroy(); //取消注册 , 防止Activity内存泄漏 EventBus.getDefault().unregister( this ); } }
线程模型
在接收事件消息的方法中,可以通过注解的方式设置线程模型,EventBus内置了4中线程模型,分别是ThreadMode.POSTING 、ThreadMode.MAIN、ThreadMode.BACKGROUND、ThreadMode.ASYNC
比如:
@Subscribe(threadMode = ThreadMode.POSTING) public void onMessageEventPostThread(String event) { Log.e( "event PostThread", "消息: " + event + " thread: " + Thread.currentThread().getName() ); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEventMainThread(String event) { Log.e( "event MainThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEventBackgroundThread(String event) { Log.e( "event BackgroundThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onMessageEventAsync(String event) { Log.e( "event Async", "消息: " + event + " thread: " + Thread.currentThread().getName()); }
PostThread:如果使用事件处理函数指定了线程模型为PostThread,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为PostThread的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
MainThread:如果使用事件处理函数指定了线程模型为MainThread,那么不论事件是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。该方法可以用来更新UI,但是不能处理耗时操作。
BackgroundThread:如果使用事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
Async:如果使用事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。同样,此事件处理函数中禁止进行UI更新操作。
小例子1: 在子线程发送数据
package com.eventbus.app; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //注册 EventBus.getDefault().register( this ); findViewById( R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Log.d( "event 发射数据线程 : " , Thread.currentThread().getName() ) ; EventBus.getDefault().post( "我发射了"); } }).start() ; } }); } @Subscribe(threadMode = ThreadMode.POSTING) public void onMessageEventPostThread(String event) { Log.e( "event PostThread", "消息: " + event + " thread: " + Thread.currentThread().getName() ); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEventMainThread(String event) { Log.e( "event MainThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEventBackgroundThread(String event) { Log.e( "event BackgroundThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onMessageEventAsync(String event) { Log.e( "event Async", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Override protected void onDestroy() { super.onDestroy(); //取消注册 , 防止Activity内存泄漏 EventBus.getDefault().unregister( this ); } }
运行结果:
D/event 发射数据线程 :: Thread-109
E/event BackgroundThread: 消息: 我发射了 thread: Thread-109
E/event PostThread: 消息: 我发射了 thread: Thread-109
E/event Async: 消息: 我发射了 thread: pool-1-thread-2
E/event MainThread: 消息: 我发射了 thread: main
小例子2: 在主线程发送数据
package com.eventbus.app; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //注册 EventBus.getDefault().register( this ); findViewById( R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d( "event 发射数据线程 : " , Thread.currentThread().getName() ) ; EventBus.getDefault().post( "我发射了"); } }); } @Subscribe(threadMode = ThreadMode.POSTING) public void onMessageEventPostThread(String event) { Log.e( "event PostThread", "消息: " + event + " thread: " + Thread.currentThread().getName() ); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEventMainThread(String event) { Log.e( "event MainThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEventBackgroundThread(String event) { Log.e( "event BackgroundThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onMessageEventAsync(String event) { Log.e( "event Async", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Override protected void onDestroy() { super.onDestroy(); //取消注册 , 防止Activity内存泄漏 EventBus.getDefault().unregister( this ); } }
运行结果:
D/event 发射数据线程 :: main
E/event MainThread: 消息: 我发射了 thread: main
E/event PostThread: 消息: 我发射了 thread: main
E/event Async: 消息: 我发射了 thread: pool-1-thread-3
E/event BackgroundThread: 消息: 我发射了 thread: pool-1-thread-4
黏性事件
除了上面讲的普通事件外,EventBus还支持发送黏性事件。何为黏性事件呢?简单讲,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。具体用法如下:
注册
EventBus.getDefault().register( this );
事件接收
@Subscribe(threadMode = ThreadMode.MAIN , sticky = true ) public void onMessageEventMainThread(String event) { Log.e( "event MainThread", "消息: " + event + " thread: " + > Thread.currentThread().getName()); }
取消注册
EventBus.getDefault().unregister( this ) ;
发送事件
EventBus.getDefault().postSticky( "我发射了");
小例子:在MainActivity发送事件,在Activity2里注册并且接收事件
MainActivity源码
package com.eventbus.app; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import org.greenrobot.eventbus.EventBus; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById( R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d( "event 发射数据线程 : " , Thread.currentThread().getName() ) ; EventBus.getDefault().postSticky( "我发射了"); startActivity( new Intent( MainActivity.this , Activity2.class )); } }); } }
Activity2源码
package com.eventbus.app; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class Activity2 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_2); //注册 EventBus.getDefault().register( this ); } @Subscribe(threadMode = ThreadMode.MAIN , sticky = true ) public void onMessageEventMainThread(String event) { Log.e( "event MainThread", "消息: " + event + " thread: " + Thread.currentThread().getName()); } @Override protected void onDestroy() { super.onDestroy(); //取消注册 , 防止Activity内存泄漏 EventBus.getDefault().unregister( this ) ; } }
这就是粘性事件,能够收到订阅之前发送的消息。但是它只能收到最新的一次消息,比如说在未订阅之前已经发送了多条黏性消息了,然后再订阅只能收到最近的一条消息。
EventBus源码分析
Subscribe 接口源码
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; /** * If true, delivers the most recent sticky event (posted with * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). */ boolean sticky() default false; /** Subscriber priority to influence the order of event delivery. * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of * delivery among subscribers with different {@link ThreadMode}s! */ int priority() default 0; }
可以看出默认的线程模型是ThreadMode.POSTING ;默认黏性事件为false,也就是默认不开启黏性事件;默认的优选级为0 。
EventBus 类部分源码
static volatile EventBus defaultInstance; /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
getDefault() 是一个单例模式 , 只有一个实例对象。
ThreadMode 类源码
public enum ThreadMode { /** * Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery * implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for * simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread. */ POSTING, /** * Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is * the main thread, event handler methods will be called directly. Event handlers using this mode must return * quickly to avoid blocking the main thread. */ MAIN, /** * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single * background thread, that will deliver all its events sequentially. Event handlers using this mode should try to * return quickly to avoid blocking the background thread. */ BACKGROUND, /** * Event handler methods are called in a separate thread. This is always independent from the posting thread and the * main thread. Posting events never wait for event handler methods using this mode. Event handler methods should * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number * of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus * uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. */ ASYNC }
这个类是枚举类,定义了线程模型中的几种类型。
以上这篇Android EventBus 3.0.0 使用总结(必看篇)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
本文向大家介绍Eclipse常用快捷键总结(必看篇),包括了Eclipse常用快捷键总结(必看篇)的使用技巧和注意事项,需要的朋友参考一下 Alt+/ 内容辅助 最常用的快捷键,省去了自己一个字一个字敲代码的时间 Ctrl+Shift+F 格式化文档 Ctrl+Shift+O
本文向大家介绍javaScript知识点总结(必看篇),包括了javaScript知识点总结(必看篇)的使用技巧和注意事项,需要的朋友参考一下 1、javaScript的概念:是一种表述语言,也是一种基于对象(Object)和事件驱动(EventDriven)的,安全性好的脚本语言,运行在客户端,从而减轻服务器端的负担,总结如下: 1.javaScript主要用来向HTML页面找那个添加交互行
本文向大家介绍jQuery学习心得总结(必看篇),包括了jQuery学习心得总结(必看篇)的使用技巧和注意事项,需要的朋友参考一下 jQuery 对象 •jQuery 对象就是通过 jQuery 包装 DOM 对象后产生的对象。 •jQuery 对象是 jQuery 独有的。 •只有 jQuery 对象才能使用 jQuery 的方法,在 jQuery 对象中无法使用 DOM 对象的任何方法,反之
本文向大家介绍js字符串操作总结(必看篇),包括了js字符串操作总结(必看篇)的使用技巧和注意事项,需要的朋友参考一下 字符方法 字符串操作方法 concat方法 slice方法、substring方法、substr方法 字符串位置方法 trim方法 字符串大小写转换方法 字符串模式匹配方法 replace方法 split方法 localeCompare方法 fromCharCode方法 找到匹配
本文向大家介绍Java中的对象流总结(必看篇),包括了Java中的对象流总结(必看篇)的使用技巧和注意事项,需要的朋友参考一下 Java中可以通过对象流将一个序列化的对象保存到硬盘中,或者硬盘中读取一个对象。对象流的存储和读取包含以下几点内容: 1、所保存的对象必须实现Serializable接口。 2、 所保存的对象的属性也必须实现Serializable接口。 3、 最好要给该对象提供一个版本
硬件建议 从上一讲的安装教程来看,IntelliJ IDEA 对硬件的要求看上去不是很高。可是实际在开发中其实并不是这样的,特别是开发 Java Web 的项目的计算机,2G 内存是基本不够用的。 我们现在来假设一种国内常见的开发环境: 有一个在开发的 Java Web 项目,它使用的框架为主流的:Struts + Spring + Hibernate,使用这三个框架的过程中,我们要引入大量的框架