Android EventBus

1.EventBus概述

EventBus出自greenrobot,和之前大名鼎鼎的GreenDao出自同一家。之前一直
使用的是2.4版本,今天我們將學(xué)習(xí)分析最新的Event 3.0,EventBus 3.0 最新的
特性就是加入了注解,通過注解的方式 告知訂閱函數(shù)運行在哪個線程中。

2.EventBus好處

EventBus是一款針對Android優(yōu)化的發(fā)布/訂閱事件總線。主要功能是替代
Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息.優(yōu)
點是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。

3.EventBus框架中涉及四個成分

訂閱者,發(fā)布者,訂閱事件,事件總線
register訂閱,unregister取消訂閱,post發(fā)布,接收事件

EventBus主要角色:
    Event       傳遞的事件對象
    Subscriber  事件的訂閱者 
    Publisher   事件的發(fā)布者
    ThreadMode  定義函數(shù)在何種線程中執(zhí)行

4.ThreadMode總共四個:

2.x版:
    onEvent:
        使用onEvent作為訂閱函數(shù),那么該事件在哪個線程發(fā)布出來的,    
         onEvent就會在這個線程中運行,也就是說發(fā)布事件和接收事件線程在同一個線程。
    onEventMainThread:
        無論事件在哪個線程發(fā)布出來的,始終在UI線程中執(zhí)行訂閱事件的操作。
    onEventBackground:
        無論事件在哪個線程發(fā)布出來的,始終在工作線程中執(zhí)行訂閱事件的操作。
    onEventAsync:
        使用這個函數(shù)作為訂閱函數(shù),那么無論事件在哪個線程發(fā)布,都會創(chuàng)建新的子線程在執(zhí)行onEventAsync.

3.0版:
    POSTING 和發(fā)布者處在同一個線程
    MAIN UI主線程
    BACKGROUND 后臺線程
    ASYNC 異步線程

EventBus配置:

build.gradle添加引用 
    implementation 'org.greenrobot:eventbus:3.0.0'

EventBus代碼案例使用:

事件類型

public class DataSynEvent {
    private int count;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

訂閱

EventBus.getDefault().register(this);

解除訂閱

EventBus.getDefault().unregister(this);

發(fā)布事件

EventBus.getDefault().post(new DataSynEvent());

訂閱事件處理

//在ui(主)線程執(zhí)行
@Subscribe(threadMode = ThreadMode.MAIN)
public void onDataSynEvent(DataSynEvent event) {
    Log.e(TAG, "event---->" + event.getCount());
}

ThreadMode

ThreadMode總共四個:
    MAIN UI主線程
    BACKGROUND 后臺線程
    POSTING 和發(fā)布者處在同一個線程
    ASYNC 異步線程

優(yōu)先級

  事件的優(yōu)先級類似廣播的優(yōu)先級,優(yōu)先級越高優(yōu)先獲得消息
  //在ui線程執(zhí)行 優(yōu)先級100
@Subscribe(threadMode = ThreadMode.MAIN,priority = 100) 
public void onDataSynEvent(DataSynEvent event) {
    Log.e(TAG, "event---->" + event.getCount());
}

發(fā)送有序廣播可以終止廣播的繼續(xù)往下傳遞,EventBus也實現(xiàn)了此功能
//優(yōu)先級高的訂閱者可以終止事件往下傳遞
EventBus.getDefault().cancelEventDelivery(event) ;

EventBus黏性事件

EventBus黏性事件概述
EventBus除了普通事件也支持粘性事件,這個有點類似廣播分類中的粘性廣
播。本身粘性廣播用的就比較少,為了方便理解成訂閱在發(fā)布事件之后,但同樣
可以收到事件。訂閱/解除訂閱和普通事件一樣,但是處理訂閱函數(shù)有所不同,需要注解中添加sticky = true
訂閱粘性事件處理
 //在ui線程執(zhí)行
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true) 
public void onDataSynEvent(DataSynEvent event) {
    Log.e(TAG, "event---->" + event.getCount());
}
發(fā)送粘性事件
EventBus.getDefault().postSticky(new DataSynEvent());
移除粘性事件
 對于粘性廣播我們都比較清楚屬于常駐廣播,對于EventBus粘性事件也類似,
我們?nèi)绻辉傩枰撜承允录覀兛梢砸瞥?EventBus.getDefault().removeStickyEvent(new DataSynEvent());
或者調(diào)用移除所有粘性事件
EventBus.getDefault().removeAllStickyEvents();

EventBus優(yōu)缺點:

優(yōu)點:簡化組件之間的通信方式,實現(xiàn)解耦讓業(yè)務(wù)代碼更加簡潔,可以動態(tài)設(shè)置  
事件處理線程以及優(yōu)先級
缺點:目前發(fā)現(xiàn)唯一的缺點就是類似之前策略模式一樣的詬病,每個事件都必須
自定義一個事件類,造成事件類太多,無形中加大了維護(hù)成本

EventBus 3.0 與2.x的區(qū)別

1)代碼更加簡潔
onEvent                   
@Subscribe(threadMode = ThreadMode.POSTING)

onEventMainThread     
@Subscribe(threadMode = ThreadMode.MAIN)

onEventBackgroundThread   
@Subscribe(threadMode = ThreadMode.BACKGROUND)

onEventAsync     
@Subscribe(threadMode = ThreadMode.ASYNC)

EventBus  3.0 函數(shù)名字不再受到權(quán)限,而且可以在一個函數(shù)中體現(xiàn)出在哪個線              
程執(zhí)行,并且可指定接收事件的優(yōu)先級

EventBus  2.x 注冊方式也比較繁瑣
EventBus  3.0 注冊方式只有一個

2)性能更優(yōu)
EventBus 2.x 是采用反射的方式對整個注冊的類的所有方法進(jìn)行掃描來完成注
 冊,當(dāng)然會有性能上的影響。EventBus  3.0中EventBus提供了  
EventBusAnnotationProcessor注解處理器來在編譯期通過讀取@Subscribe()注
解并解析、處理其中所包含的信息,然后生成java類來保存所有訂閱者關(guān)于訂閱    
的信息,這樣就比在運行時使用反射來獲得這些訂閱者的信息速度要快

代碼混淆

復(fù)制代碼
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

Only required if you use AsyncExecutor

-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}

反射:

獲取類

Class aClass = Class.forName("com.jiyun.lzj");

獲取構(gòu)造

Constructor constructor = aClass.getConstructor();
Object obj = constructor.newInstance();

獲取方法

Method aaa = aClass.getDeclaredMethod("AAA");
String str = (String) aaa.invoke(this,key);

 //可以調(diào)用類中的所有方法(不包括父類中繼承的方法) 
Method method=clazz.getDeclaredMethod(name);
//可以調(diào)用類中有訪問權(quán)限的方法(包括父類中繼承的方法)
Method method=clazz.getMethod(name);

//獲取方法1:私有無參有返回值方法
Method getData = aClass.getDeclaredMethod("getData");
getData.setAccessible(true);//設(shè)置方法私有方法的權(quán)限
String string = (String) getData.invoke(preson1);
System.out.println(string);

//獲取方法2:私有有參無返回值方法
Method show = aClass.getDeclaredMethod("show", String.class);
show.setAccessible(true);//設(shè)置方法私有方法的權(quán)限
show.invoke(preson1,"張三");

獲取字段

Field btn =  aClass.getDeclaredField("btn");

獲取注解

boolean annotationPresent = aClass.isAnnotationPresent(MyAnnotation.class);
MyAnnotation myAnnotation = (MyAnnotation) aClass.getAnnotation(MyAnnotation.class);

注解(搭配反射使用)

1.普通注解:

@Override 方法覆蓋父類方法
@Deprecated 出現(xiàn)警告信息
@SuppressWarnings() 忽略警告信息

2.元注解:

@Documented 被JavaDoc工具記錄
@Target()  注解使用范圍,使用位置
      ElementType.
              ANNOTATION_TYPE,注解
              CONSTRUCTOR,構(gòu)造
              FIELD,成員變量
              LOCAL_VARIABLE,局部變量
              METHOD,方法
              PACKAGE,包
              PARAMETER,參數(shù)
              TYPE,類接口
              TYPE_PARAMETER,
              TYPE_USE;

@Retention()  注解使用生命周期,作用
      RetentionPolicy.  
              SOURCE源碼說明   
              CLASS編譯時注解     
              RUNTIME運行時注解

@Inherited  注解繼承

Override案例:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {

}

自定義注解:

/**
 * 自定義注解,反射獲取使用
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    //@IdRes int value();
    int MyValue() default 0;

    String MyStringValue() default "";
}

/**
 * 使用自定義注解
 */
@MyAnnotation(MyValue = R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);

        /**
         * 反射加載
         */
        Class aClass = this.getClass();
        Class bClass = MainActivity.class;
        try {
            Class cClass1 = Class.forName("com.example.lizhengjun.demobutterknife.MainActivity");

            if (cClass1.isAnnotationPresent(MyAnnotation.class)){

                MyAnnotation annotation = (MyAnnotation) cClass1.getAnnotation(MyAnnotation.class);
                int layout = annotation.MyValue();

                Method setContentView = cClass1.getMethod("setContentView", int.class);

                setContentView.invoke(this,layout);
                //setContentView(layout);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

ButterKnife使用

ButterKnife依賴插件:

依賴:
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

插件:
    Android ButterKnife Zelezny

獲取控件、事件點擊處理

Activity使用:

public class MainActivity extends AppCompatActivity {

    //獲取控件
    @BindView(R.id.name)
    EditText name;

    @BindView(R.id.btn)
    Button btn;
    @BindView(R.id.txt)
    TextView txt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //綁定處理
        ButterKnife.bind(this);
    }

    //按鈕點擊事件處理
    @OnClick(R.id.btn)
    public void onViewClicked() {

        if (TextUtils.isEmpty(name.getText().toString().trim())){
            return;
        }

        if (name.getText().toString().trim().length() < 6){
            return;
        }

        txt.setText(name.getText());
    }
}

Fragment使用:

public class BlankFragment extends Fragment {


    @BindView(R.id.txt)
    TextView txt;
    @BindView(R.id.btn)
    Button btn;


    Unbinder unbinder;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View inflate = inflater.inflate(R.layout.fragment_blank, container, false);
        unbinder = ButterKnife.bind(this, inflate);
        return inflate;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

    @OnClick(R.id.btn)
    public void onViewClicked() {

    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容