zoukankan      html  css  js  c++  java
  • Android EventBus 3.0 实例使用详解

    EventBus的使用和原理在网上有很多的博客了,其中泓洋大哥启舰写的非常非常棒,我也是跟着他们的博客学会的EventBus,因为是第一次接触并使用EventBus,所以我写的更多是如何使用,源码解析就不怎么样啦!

    如需转载请注明出处:Android EventBus 3.0 实例使用详解

    一、概述

    EventBus是一款Android下的发布/订阅事件总线机制。可以代替Intent、Handler、Broadcast等在Fragment、Activity之间传递消息。
    优点:开销小,代码优雅。将发送者和接受者解耦。
    既然是有关于事件的发布和订阅,那么发布者和订阅者的关系又是怎样的呢?
    事件的发布者可以发布多个事件,发布者同时也可以是订阅者,订阅者可以订阅多个事件。
    二、实例
    接下来要通过实例来讲解如何使用EventBus了,在看代码之前要记得三个问题。
    1、事件发布者如何发布事件
    2、事件订阅者如何订阅事件
    3、订阅者如何准确接收发布者发布的多个事件中的一个(假设发布者发布多个事件,订阅者只是订阅其中的一个事件)
    (1)首先在gradle文件中添加EventBus的依赖
    compile 'org.greenrobot:eventbus:3.0.0'

    (2)在相关Activity中的onCreat()、onDestory()注册和解注EventBus

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            EventBus.getDefault().register(this);
        }
    
    @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }

    (3)事件发布者如何发布事件

    EventBus.getDefault().post(实参);

    我们到.getDefault()来看一个这个方法:

    /** 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()方法其实就是一个单例,获取到EventBus实例后调用post方法开始发布事件

    post():

    /** Posts the given event to the event bus. */
        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;
                }
            }
        }

    通过源码可以看得出来,方法的实参是一个对象类型的参数,参数会统一存储在eventQueue这个队列中,然后循环队列,将队列中的消息逐一发布,这里大家可能会想,每次post都会去调用整个队列么,那么不会造成方法多次调用么?

    答案是不会的,因为在最外层加了一个判断,判断event是否被发布过,如果被发布过,则不会进入到这个方法内。

    (4)事件订阅者订阅事件

    @Subscribe
        public void onEventMainThread(实参){
            //接收到发布者发布的事件后,进行相应的处理操作
        }

    这里要注意的是:EventBus在 3.0 版本后,事件订阅监听的方法名可以随意起,不同于旧版本,名字是特定的。

    public void onEventMainThread(param)  
        {  
       //如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,
       //这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
    }
    public void onEventPostThread(param) { //如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。
       //使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
    }
    public void onEventBackgroundThread(param) { //如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。 } public void onEventAsync(param) {   //使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync. }

    但是新版本需要手动的添加注解@Subscribe(这是必不可少的)。既然名字可以随意起,那么又怎么控制在什么线程内进行处理呢?

    @Subscribe(threadMode = ThreadMode.MAIN)

    给注解设置ThreadMode就可以了。

    (5)事件发布者和订阅者如何对应上

    可以看到发布事件和订阅事件,都需要传入一个实参,而且在post方法中我们也看到了,这个实参是对象类型的,大家猜想的话也可以知道,发布和订阅事件是通过一个对象实参来进行关联的。

    public class TestEvent {
        private int mMsg;
        public TestEvent(int msg) {
            mMsg = msg;
        }
        public int getMsg(){
            return mMsg;
        }
    }

    这个类很简单,只有一个变量和一个构造方法、get方法。具体内容根据项目需求来定。

    基本上了解这些就可以搞明白EventBus的使用了,下面上一下我写的Demo,功能很简单,就是模仿下载的进度条,因为现在用的最多的是通过handler来进行处理的,而EventBus的出现,可以完美的代替handler,

    而且实现了解耦。

    好,上代码!

    MainActivity.class

    package com.example.wgh.eventbusdemo;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ProgressBar;
    
    import org.greenrobot.eventbus.EventBus;
    import org.greenrobot.eventbus.Subscribe;
    import org.greenrobot.eventbus.ThreadMode;
    
    
    public class MainActivity extends Activity {
    
        public ProgressBar progressBar = null;
        public int time = 0;
        @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) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            while (time<100){
                                time += 15;
                                EventBus.getDefault().post(new TestEvent(time));
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }).start();
                }
            });
            progressBar = (ProgressBar) findViewById(R.id.progressbar);
    
            EventBus.getDefault().register(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }
        @Subscribe(threadMode = ThreadMode.MAIN)
        public void onEventMainThread(TestEvent event){
            progressBar.setProgress(event.getMsg());
        }
    }

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.wgh.eventbusdemo.MainActivity"
        android:orientation="vertical">
    
        <ProgressBar
            android:id="@+id/progressbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="150dp"
            android:max="100"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>
        <Button
            android:id="@+id/button"
            android:layout_marginTop="10dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="开始下载"/>
    </LinearLayout>

    TestEvent.class

    public class TestEvent {
        private int mMsg;
        public TestEvent(int msg) {
            mMsg = msg;
        }
        public int getMsg(){
            return mMsg;
        }
    }

    补充知识点:粘性事件

    public class SecondActivity extends Activity {
        private TextView textView = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            textView = (TextView) findViewById(R.id.test);
            EventBus.getDefault().register(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }
    
        @Subscribe(threadMode = ThreadMode.MAIN)
        public void wgh2(TestEvent event){
            textView.setText("同样接收到了msg"+event.getMsg());
        }
    }

    发现SecondActivity中没有订阅到发布的事件,查了下资料才知道,在MainActivity中发布了事件,但是到了SecondActivity中没有订阅到,这里就需要用到粘性事件了

    所谓粘性事件指的就是事件发布之后再订阅该事件,仍然可以收到该事件,这部分与普通事件的区别是:普通事件是先注册再绑定

    所以代码方面就需要做一下调整

    MainActivity

    EventBus.getDefault().postSticky(new TestEvent(time));

    SecondActivity

    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
        public void wgh2(TestEvent event){
            textView.setText("同样接收到了msg"+event.getMsg());
        }

    经过试验之后发现就生效了!!!

  • 相关阅读:
    SQL SERVER XML 学习总结
    Azkaban2官方配置文档
    I.MX6 Android CAN 命令行测试
    nginx 静态网站配置
    nginx php 配置
    uwsgi 配置 初试
    django 初试
    Ubuntu Nginx uwsgi django 初试
    I.MX6 天嵌 E9 U-boot menu hacking
    Ubuntu 搭建 LAMP 服务器
  • 原文地址:https://www.cnblogs.com/upwgh/p/6394901.html
Copyright © 2011-2022 走看看