Android EventBus 3.0.0 使用總結

轉載請標明出處:http://www.cnblogs.com/zhaoyanjun/p/6039221.html
本文出自【趙彥軍的博客】html

前言

  • EventBus框架android

    EventBus是一個通用的叫法,例如Google出品的Guava,Guava是一個龐大的庫,EventBus只是它附帶的一個小功能,所以實際項目中使用並很少。用的最多的是greenrobot/EventBus,這個庫的優勢是接口簡潔,集成方便,可是限定了方法名,不支持註解。另外一個庫square/otto修改自 Guava ,用的人也很多。因此今天咱們研究的目標是greenrobot的EventBus.git

  • EventBus 簡介github

    一、EventBus3.0.0 是最新的版本。
    二、EventBus 是Android 發佈/訂閱事件總線,可簡化 Activities, Fragments, Threads, Services 等組件間的消息傳遞。
    三、可替代 Intent, Handler, BroadCast ,接口等傳統方案,更快,代碼更小,50K 左右的 jar 包,代碼更優雅,完全解耦。app

github地址:https://github.com/greenrobot/EventBus框架

EventBus原理圖async

這裏寫圖片描述

如何添加依賴

  • 在module的build.gredle 文件中的dependencies標籤中添加ide

    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.POSTINGThreadMode.MAINThreadMode.BACKGROUNDThreadMode.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
}

這個類是枚舉類,定義了線程模型中的幾種類型。

參考資料

【EventBus 3.0的用法詳解】
【EventBus使用詳解】
【騰訊Bugly乾貨】老司機教你「飆」EventBus3】

相關文章
相關標籤/搜索