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 {

    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(1000, myCity))

        // 发送第二条消息
        Student myStu = new Student();
        myStu.setStudentName("张三");
        EventBus.getDefault().post(new MessageEvent(2000, myStu))
    }
}

以上发送者,同时发送了两条毫不相干的消息,其中两条消息的message设置的不同,MessageEvent的泛型也设为需要发送的类型。

订阅者:

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 msg) {
        if (msg.getMessage() == 1000) {
            City city = msg.getBody();      // 泛型自动把City转化回来
            Log.d("TAG","-->> City Name = " + city.getCityName());
        }
    }

    /**
     * 接收学生实体
     */
    @Subscribe
    public void getStudentFromEventBus(final MessageEvent 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是无法解决的,此时需要使用广播等方式来解决。

你可能感兴趣的:(EventBus的使用与泛型的封装)