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() {
}
}