EventBus的使用与泛型的封装
前言
在Android开发中我们经常会碰到Activity、Fragment、Application等对象之间的传递参数问题;然而,它们之间单向通信简单,但遇到多Fragment相互传参通信,或是多Activity之间的异步通信,就需要EventBus出面。
当然,你也可以使用,以下传统的方法:
activity.setArgument(Bundle bundle); // Activity向Fragment发送数据
activity.startActivity(intent); // Activity向Activity发送数据
activity.startActivityForResult(..., ...)
...
EventBus的概念
如同前言所说,EventBus是简化一个APP的内部通信问题,解决多个Activity、Fragment、Application、业务类、工具类等任何Android实体类之间的通信(除了Service)。
EventBus以反射为核心,线程为载体,使用事件“订阅者”与“发送者”的概念,降低模块间的耦合,并且支持多线程。
但由于它是使用的是反射,所以不支持与Service之间通信。
如何使用
使用场景:
两个以上Activity之间信息交互;
群发消息给多个Activity、Fragment、业务类等;
Application实时发送消息给Activity、Fragment、业务类等。
场景不止于此,EventBus适用范围非常广泛。
app/build.gradle中的配置
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
}
所以,根据它的“订阅者”与“发送者”的概念,其使用大致分为两步:
第一步、注册“订阅者”
public class TestFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
EventBus.getDefault().register(this); // 注册订阅
// ...
return inflater.inflate(R.layout.fragment_test, container, false);
}
/**
* 接收订阅消息后,会进入以下代码
*/
@Subscribe
public void getMessageByEventBus(String message) {
// 打印接收到的消息
Log.d("TAG","-->> Message = " + message);
}
@Override
public void onDestroyView() {
super.onDestroyView();
EventBus.getDefault().unregister(this); // 取消订阅
}
}
以上代码包含三个部分:
1、在onCreateView()中注册订阅
2、使用@Subscribe对一个任意方法标上注解
3、在onDestroyView()中注销订阅
不一定在onCreate里注册,但一定要在“发送”之前进行注册,否则会@Subscribe注解的方法将接收不到消息。
建议在生命周期结束结束时取消订阅。
第二步、发送!
public class TestActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// ...
// 只需要这句话即可发送
EventBus.getDefault().post("今天天气不错");
// ...
}
}
以上代码EventBus.getDefault().post("")
,不仅在Activity中,它还可以写在任何实体类里。
比如下面的这个工具类:
object CityUtil {
fun getCityName() {
EventBus.getDefault().post("南京")
}
}
当执行过post()
方法之后,整个进程内,所有被@Subscribe
所订阅过的方法,都将收到其发送的信息。例子中我只用post方法传递了String做演示,实际上post(Object)
所以可以把任何的对象丢进去进行传递。
泛型的封装
当我们有多个订阅者在同一进程内运行时,每个订阅者难免会接收到不是自己所订阅的消息,所以这时候我们需要使用规范来区分不同订阅者所订阅的消息。
消息实体:
/**
* 这是通配的消息泛型类,不用修改复制进程序里即可
**/
public class MessageEvent<T> {
private int message; // 这里的message类似于RequestCode
private T body; // 这是需要作为消息的实体
public MessageEvent(int message, T body) {
this.message = message;
this.body = body;
}
public int getMessage() {
return message;
}
public T getBody() {
return body;
}
}
以上消息实体类中,我们可以把message看做一个requestCode,使订阅者与发送者的message保持一致,这样就可以过滤掉不属于自己订阅的多余消息。
发送者:
public class TestActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// 发送第一条消息
City myCity = new City();
myCity.setCityName("南京");
EventBus.getDefault().post(new MessageEvent<City>(1000, myCity))
// 发送第二条消息
Student myStu = new Student();
myStu.setStudentName("张三");
EventBus.getDefault().post(new MessageEvent<Student>(2000, myStu))
}
}
以上发送者,同时发送了两条毫不相干的消息,其中两条消息的message设置的不同,MessageEvent<T>的泛型也设为需要发送的类型。
订阅者:
public class TestFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
EventBus.getDefault().register(this); // 注册订阅
// ...
return inflater.inflate(R.layout.fragment_test, container, false);
}
/**
* 接收城市实体
*/
@Subscribe
public void getCityFromEventBus(final MessageEvent<City> msg) {
if (msg.getMessage() == 1000) {
City city = msg.getBody(); // 泛型自动把City转化回来
Log.d("TAG","-->> City Name = " + city.getCityName());
}
}
/**
* 接收学生实体
*/
@Subscribe
public void getStudentFromEventBus(final MessageEvent<Student> msg) {
if (msg.getMessage() == 2000) {
Student stu = msg.getBody(); // 泛型自动把Student转化回来
Log.d("TAG","-->> Student Name = " + stu .getStudentName());
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
EventBus.getDefault().unregister(this); // 取消订阅
}
}
以上的订阅者中,他接收了由发送者同时发来的两个不同的消息,并且分别进行处理打印,Demo中的Student和City两个实体类就在此呈现。
结束语
使用泛型封装过的实体类,可以进一步加强EventBus的适用性,一是简化规范了代码,二是使用时更加方便。但在遇到Service与线程之间通信时EventBus是无法解决的,此时需要使用广播等方式来解决。