前言

前段时间给GeekNews做了一部分重构和修改,记录下来大致可以分为三点:

  • 基类的改动
  • Model层的改动
  • RxJava相关

基类的改动

这次改动新增了RootActivity,并且让BaseActivity继承了SimpleActivity,各层职责明确,最后形成了如下的继承关系链:

RootActivity –> BaseActivity –> SimpleActivity –> SupportActivity –> Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public abstract class SimpleActivity extends SupportActivity {
protected Activity mContext;
private Unbinder mUnBinder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout());
mUnBinder = ButterKnife.bind(this);
mContext = this;
onViewCreated();
App.getInstance().addActivity(this);
initEventAndData();
}
protected void setToolBar(Toolbar toolbar, String title) {
toolbar.setTitle(title);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onBackPressedSupport();
}
});
}
protected void onViewCreated() {
}
@Override
protected void onDestroy() {
super.onDestroy();
App.getInstance().removeActivity(this);
mUnBinder.unbind();
}
protected abstract int getLayout();
protected abstract void initEventAndData();
}

抽象类SimpleActivity继承自FragmentationSupportActivity,负责完成布局渲染,控件注入,初始化Toolbar的工作,封装度低,非常灵活,可以自由扩展,通常用于不需要Presenter层的简单页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public abstract class BaseActivity<T extends BasePresenter> extends SimpleActivity implements BaseView {
@Inject
protected T mPresenter;
protected ActivityComponent getActivityComponent(){
return DaggerActivityComponent.builder()
.appComponent(App.getAppComponent())
.activityModule(getActivityModule())
.build();
}
protected ActivityModule getActivityModule(){
return new ActivityModule(this);
}
@Override
protected void onViewCreated() {
super.onViewCreated();
initInject();
if (mPresenter != null)
mPresenter.attachView(this);
}
@Override
protected void onDestroy() {
if (mPresenter != null)
mPresenter.detachView();
super.onDestroy();
}
@Override
public void showErrorMsg(String msg) {
SnackbarUtil.show(((ViewGroup) findViewById(android.R.id.content)).getChildAt(0), msg);
}
@Override
public void useNightMode(boolean isNight) {
if (isNight) {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_NO);
}
recreate();
}
@Override
public void stateError() {
}
@Override
public void stateLoading() {
}
@Override
public void stateMain() {
}
protected abstract void initInject();
}

抽象类BaseActivity继承自SimpleActivity, 由于附带了<T extends BasePresenter>的泛型并且实现了BaseView的接口,使它具备了与Presenter交互的能力,在这里完成依赖注入和Presenter的绑定,通常用于普通MVP结构中的View层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public abstract class RootActivity<T extends BasePresenter> extends BaseActivity<T>{
private static final int STATE_MAIN = 0x00;
private static final int STATE_LOADING = 0x01;
private static final int STATE_ERROR = 0x02;
private ProgressImageView ivLoading;
private LinearLayout viewError;
private FrameLayout viewLoading;
private ViewGroup viewMain;
private int currentState = STATE_MAIN;
@Override
protected void initEventAndData() {
viewMain = (ViewGroup) findViewById(R.id.view_main);
if (viewMain == null) {
throw new IllegalStateException(
"The subclass of RootActivity must contain a View named view_main.");
}
if (!(viewMain.getParent() instanceof ViewGroup)) {
throw new IllegalStateException(
"view_main's ParentView should be a ViewGroup");
}
ViewGroup parent = (ViewGroup) viewMain.getParent();
View.inflate(mContext, R.layout.view_error, parent);
View.inflate(mContext, R.layout.view_progress, parent);
viewError = (LinearLayout) parent.findViewById(R.id.view_error);
viewLoading = (FrameLayout) parent.findViewById(R.id.view_loading);
ivLoading = (ProgressImageView) viewLoading.findViewById(R.id.iv_progress);
viewError.setVisibility(View.GONE);
viewLoading.setVisibility(View.GONE);
viewMain.setVisibility(View.VISIBLE);
}
@Override
public void stateError() {
if (currentState == STATE_ERROR)
return;
hideCurrentView();
currentState = STATE_ERROR;
viewError.setVisibility(View.VISIBLE);
}
@Override
public void stateLoading() {
if (currentState == STATE_LOADING)
return;
hideCurrentView();
currentState = STATE_LOADING;
viewLoading.setVisibility(View.VISIBLE);
ivLoading.start();
}
@Override
public void stateMain() {
if (currentState == STATE_MAIN)
return;
hideCurrentView();
currentState = STATE_MAIN;
viewMain.setVisibility(View.VISIBLE);
}
private void hideCurrentView() {
switch (currentState) {
case STATE_MAIN:
viewMain.setVisibility(View.GONE);
break;
case STATE_LOADING:
ivLoading.stop();
viewLoading.setVisibility(View.GONE);
break;
case STATE_ERROR:
viewError.setVisibility(View.GONE);
break;
}
}
}

抽象类RootActivity继承自BaseActivity ,进一步实现了BaseView中的几个state控制方法,使页面具备了在ErrorLoadingMain等状态间自由切换的能力,实现的原理是首先将当面页面布局文件中显示主体内容的控件命名为view_main,随后在initEventAndData 方法中会自动寻找view_main,并在同一层级中动态添加Error与Loading视图,然后在各state方法中控制各状态页面的显隐。按照这个思路,根据自己的需求还可以添加EmptyNoNetWorking等状态视图,如果状态视图比较复杂,为了性能可以把状态视图定义为ViewStub,实际用到时才去渲染

Model层的改动

这次改动抽象出了HttpHelperDBHelperPreferencesHelper这些接口,RealmHelperRetrofitHelper等只是做为接口的一种实现,这样显然要合理的多。并且添加了DataManager做为数据分发中心,DataManager分别实现了HttpHelper, DBHelper, PreferencesHelper接口,具体实现还是交由各子Helper类来完成,这样的好处是对上层屏蔽了数据来源,Presenter层无论需要什么数据都可以从DataManager中取,各Helper类由Dagger2注入到DataManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Module
public class AppModule {
private final App application;
public AppModule(App application) {
this.application = application;
}
@Provides
@Singleton
App provideApplicationContext() {
return application;
}
@Provides
@Singleton
HttpHelper provideHttpHelper(RetrofitHelper retrofitHelper) {
return retrofitHelper;
}
@Provides
@Singleton
DBHelper provideDBHelper(RealmHelper realmHelper) {
return realmHelper;
}
@Provides
@Singleton
PreferencesHelper providePreferencesHelper(ImplPreferencesHelper implPreferencesHelper) {
return implPreferencesHelper;
}
@Provides
@Singleton
DataManager provideDataManager(HttpHelper httpHelper, DBHelper DBHelper, PreferencesHelper preferencesHelper) {
return new DataManager(httpHelper, DBHelper, preferencesHelper);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DataManager implements HttpHelper, DBHelper, PreferencesHelper {
HttpHelper mHttpHelper;
DBHelper mDbHelper;
PreferencesHelper mPreferencesHelper;
public DataManager(HttpHelper httpHelper, DBHelper dbHelper, PreferencesHelper preferencesHelper) {
mHttpHelper = httpHelper;
mDbHelper = dbHelper;
mPreferencesHelper = preferencesHelper;
}
@Override
public boolean getNightModeState() {
return mPreferencesHelper.getNightModeState();
}
@Override
public GoldManagerBean getGoldManagerList() {
return mDbHelper.getGoldManagerList();
}
@Override
public Flowable<List<RepliesListBean>> fetchRepliesList(String id) {
return mHttpHelper.fetchRepliesList(id);
}
//后续省略
}

到此Model层的改动算结束了吗?其实还有一些工作可以做,依照参考Android-CleanArchitecture,我们还可以引入MapperUseCase

Mapper(DTO->VO)

为数据添加一层Mapper映射,完成DTO->VO的转化,提高上层的稳定性,让Model层完成更多职责。

具体来说:我们从服务端拿到的原始数据可以视作DTO,我们在View层直接使用的数据则是VO,如果没有这层中间转化,直接使用从服务端取到的原始数据可以会面临参数值为null,或者接口字段不匹配等等问题,导致View层加入不必要的逻辑判断,或是伴随Model层的变动不断修改,通过加入这层Mapper映射后我们有机会把更多处理交由Model层完成,保证上层的纯净和稳定。具体内容可以看YoKey的这篇[架构向] 谈Android中DTO -> VO的重要性

摘取Android-CleanArchitecture中的一段示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@PerActivity
public class UserModelDataMapper {
@Inject
public UserModelDataMapper() {}
/**
* Transform a {@link User} into an {@link UserModel}.
*
* @param user Object to be transformed.
* @return {@link UserModel}.
*/
public UserModel transform(User user) {
if (user == null) {
throw new IllegalArgumentException("Cannot transform a null value");
}
final UserModel userModel = new UserModel(user.getUserId());
userModel.setCoverUrl(user.getCoverUrl());
userModel.setFullName(user.getFullName());
userModel.setEmail(user.getEmail());
userModel.setDescription(user.getDescription());
userModel.setFollowers(user.getFollowers());
return userModel;
}
/**
* Transform a Collection of {@link User} into a Collection of {@link UserModel}.
*
* @param usersCollection Objects to be transformed.
* @return List of {@link UserModel}.
*/
public Collection<UserModel> transform(Collection<User> usersCollection) {
Collection<UserModel> userModelsCollection;
if (usersCollection != null && !usersCollection.isEmpty()) {
userModelsCollection = new ArrayList<>();
for (User user : usersCollection) {
userModelsCollection.add(transform(user));
}
} else {
userModelsCollection = Collections.emptyList();
}
return userModelsCollection;
}
}

UseCase

根据具体业务封装出一系列UseCase,方便复用Presenter中的一些逻辑,为Presenter减压。

具体来说: Presenter层不直接使用DataManager(在Android-CleanArchitecture中被称作Repository),而是根据需求引入自己需要的UseCase来使用,UseCase则会通过DataManager取数据完成具体业务。为什么要这么做呢?因为Presenter不同于MVVM中的ViewModel,它通常与一个View层对象是强关联的,V与P一一对应,难以复用,通过把多个Presenter之间可重用的逻辑抽取成一个个UseCase,再让Presenter引入需要的UseCase,就实现了逻辑的复用。这种做法其实也是进一步细化了Model层职责的粒度,在UseCase中可以做一些额外操作减轻Presenter层的压力,如果你的P层过于臃肿,那么就要考虑加入UseCase来让Model层分摊一部分职责了。具体实践可以参考Android官方项目todo-mvp-clean,摘取其中的一段示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
public class GetStatistics extends UseCase<GetStatistics.RequestValues, GetStatistics.ResponseValue> {
private final TasksRepository mTasksRepository;
public GetStatistics(@NonNull TasksRepository tasksRepository) {
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
}
@Override
protected void executeUseCase(RequestValues requestValues) {
mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
@Override
public void onTasksLoaded(List<Task> tasks) {
int activeTasks = 0;
int completedTasks = 0;
// We calculate number of active and completed tasks
for (Task task : tasks) {
if (task.isCompleted()) {
completedTasks += 1;
} else {
activeTasks += 1;
}
}
ResponseValue responseValue = new ResponseValue(new Statistics(completedTasks, activeTasks));
getUseCaseCallback().onSuccess(responseValue);
}
@Override
public void onDataNotAvailable() {
getUseCaseCallback().onError();
}
});
}
public static class RequestValues implements UseCase.RequestValues {
}
public static class ResponseValue implements UseCase.ResponseValue {
private final Statistics mStatistics;
public ResponseValue(@NonNull Statistics statistics) {
mStatistics = checkNotNull(statistics, "statistics cannot be null!");
}
public Statistics getStatistics() {
return mStatistics;
}
}
}

介绍完了优点下面该聊一聊局限性了,MapperUseCase与所有设计模式的通病一致,会额外创建许多类,对稍大型的项目而言,可能会封装出几十个MapperUseCase,而对于逻辑简单的小型项目则是起不到什么效果,只会徒增代码量,所以在Model层是否要引入这些结构需要根据实际场景谨慎考虑,至少这次重构在经过权衡后,我还是没有引入这些结构。

RxJava相关

这次重构也由RxJava升级到了RxJava2,一些主要修改的地方如下:

Observable不再支持背压,替换为了支持背压的FlowableSubscriber被重命名为了DisposableCompositeSubscriber相应的更名为了 CompositeDisposable,在RxPresenter中做了对应修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class RxPresenter<T extends BaseView> implements BasePresenter<T> {
protected T mView;
protected CompositeDisposable mCompositeDisposable;
protected void unSubscribe() {
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}
protected void addSubscribe(Disposable subscription) {
if (mCompositeDisposable == null) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(subscription);
}
protected <U> void addRxBusSubscribe(Class<U> eventType, Consumer<U> act) {
if (mCompositeDisposable == null) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(RxBus.getDefault().toDefaultFlowable(eventType, act));
}
@Override
public void attachView(T view) {
this.mView = view;
}
@Override
public void detachView() {
this.mView = null;
unSubscribe();
}
}

RxJava2中AsyncSubjectBehaviorSubjectPublishSubjectReplaySubjectUnicastSubject保留不变,并新增了一系列支持背压的对应版本AsyncProcessorBehaviorProcessorPublishProcessorReplayProcessorUnicastProcessor, 在RxBus中做了对应修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class RxBus {
// 主题
private final FlowableProcessor<Object> bus;
// PublishSubject只会把在订阅发生的时间点之后来自原始Flowable的数据发射给观察者
private RxBus() {
bus = PublishProcessor.create().toSerialized();
}
public static RxBus getDefault() {
return RxBusHolder.sInstance;
}
private static class RxBusHolder {
private static final RxBus sInstance = new RxBus();
}
// 提供了一个新的事件
public void post(Object o) {
bus.onNext(o);
}
// 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
public <T> Flowable<T> toFlowable(Class<T> eventType) {
return bus.ofType(eventType);
}
// 封装默认订阅
public <T> Disposable toDefaultFlowable(Class<T> eventType, Consumer<T> act) {
return bus.ofType(eventType).compose(RxUtil.<T>rxSchedulerHelper()).subscribe(act);
}
}

Subscriber在RxJava2中由抽象类变成了接口,不能直接继承了,但是官方提供了一系列实现类,所以GeekNews中用于统一处理错误的CommonSubscriber改为继承了 FlowableSubscriber的实现类ResourceSubscriber, 也可以选择继承DisposableSubscriber, 他们除了FlowableSubscriber以外还实现了Disposable接口,在执行订阅方法subscribeWith后,能够返回一个Disposable用于将来取消订阅

1
2
public abstract class DisposableSubscriber<T> implements FlowableSubscriber<T>, Disposable
public abstract class ResourceSubscriber<T> implements FlowableSubscriber<T>, Disposable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public abstract class CommonSubscriber<T> extends ResourceSubscriber<T> {
private BaseView mView;
private String mErrorMsg;
private boolean isShowErrorState = true;
protected CommonSubscriber(BaseView view){
this.mView = view;
}
protected CommonSubscriber(BaseView view, String errorMsg){
this.mView = view;
this.mErrorMsg = errorMsg;
}
protected CommonSubscriber(BaseView view, boolean isShowErrorState){
this.mView = view;
this.isShowErrorState = isShowErrorState;
}
protected CommonSubscriber(BaseView view, String errorMsg, boolean isShowErrorState){
this.mView = view;
this.mErrorMsg = errorMsg;
this.isShowErrorState = isShowErrorState;
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
if (mView == null) {
return;
}
if (mErrorMsg != null && !TextUtils.isEmpty(mErrorMsg)) {
mView.showErrorMsg(mErrorMsg);
} else if (e instanceof ApiException) {
mView.showErrorMsg(e.toString());
} else if (e instanceof HttpException) {
mView.showErrorMsg("数据加载失败ヽ(≧Д≦)ノ");
} else {
mView.showErrorMsg("未知错误ヽ(≧Д≦)ノ");
LogUtil.d(e.toString());
}
if (isShowErrorState) {
mView.stateError();
}
}
}

这里也要注意RxJava2中的subscribe的重载方法不能满足目前框架对于订阅时传入一个Subscriber返回一个Disposable的需求,要使用subscribeWith方法替代

1
2
3
4
5
6
7
public final Disposable subscribe()
public final Disposable subscribe(Consumer<? super T> onNext)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Subscription> onSubscribe)
public final void subscribe(Subscriber<? super T> s)
public final void subscribe(FlowableSubscriber<? super T> s)
1
2
3
4
public final <E extends Subscriber<? super T>> E subscribeWith(E subscriber) {
subscribe(subscriber);
return subscriber;
}

为了和Java8中的Stream API保持命名风格一致,RxJava2将Action0改名为ActionAction1改名为ConsumerAction2改名为BiConsumerActionN改名为Consumer<Object[]>,将Func0java.util.concurrent.Callable<V>代替, Func1改名为FunctionFunc2改名为BiFunctionFunc3 - Func9改名为Function3-Function9FuncN 改名为Function<Object[], R>,为了兼容在很多处使用操作符的地方都做了修改(吐血

此外RxUtil中为了兼容也做了一些修改

  • Observable.OnSubscribe变为ObservableOnSubscribe,对应Flowable的版本则是FlowableOnSubscribe
  • Observable.Transformer变为ObservableTransformer,对应Flowable的版本则是FlowableTransformer
  • ObservableOnSubscribe中负责发射数据的对象由Subscriber变为ObservableEmitter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 统一线程处理
* @param <T>
* @return
*/
public static <T> FlowableTransformer<T, T> rxSchedulerHelper() { //compose简化线程
return new FlowableTransformer<T, T>() {
@Override
public Flowable<T> apply(Flowable<T> observable) {
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
/**
* 生成Flowable
* @param <T>
* @return
*/
public static <T> Flowable<T> createData(final T t) {
return Flowable.create(new FlowableOnSubscribe<T>() {
@Override
public void subscribe(FlowableEmitter<T> emitter) throws Exception {
try {
emitter.onNext(t);
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
}
}, BackpressureStrategy.BUFFER);
}

这次重构还处理了RxBus发生错误时,没有恢复订阅的bug。由于RxJava中的订阅者具有触发了一次onErroronComplete后就会不再接收事件的特性,且RxBus的事件通常只在Presenter创建时订阅一次,所以一旦发生错误后续事件就接收不到了。处理这个问题有两种方案:

方案一:在每个操作符中捕获或转化错误,确保订阅者的onError不会被触发

1
2
3
4
5
6
7
8
9
10
11
12
.flatMap(new Function<String, Flowable<DailyBeforeListBean>>() {
@Override
public Flowable<DailyBeforeListBean> apply(String date) {
Flowable<DailyBeforeListBean> bean = null;
try {
bean = mDataManager.fetchDailyBeforeListInfo(date);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
})
1
2
3
4
5
6
7
8
9
10
11
.flatMap(new Function<String, Flowable<DailyBeforeListBean>>() {
@Override
public Flowable<DailyBeforeListBean> apply(String date) {
return mDataManager.fetchDailyBeforeListInfo(date).onErrorResumeNext(new Function<Throwable, Publisher<? extends DailyBeforeListBean>>() {
@Override
public Publisher<? extends DailyBeforeListBean> apply(@NonNull Throwable throwable) throws Exception {
return Flowable.empty();
}
});
}
})

可以像上面的操作符片段中那样用try-catch捕获错误,或者在操作符内部用onErrorResumeNext将错误消息转化为空Flowable发射出去,这两种方法都可以在内部消化掉错误。但是如果在每个操作符中都如此处理,代码会非常“不优雅”,而且添加这些处理也很麻烦,这个方案走不通

方案二:在发生错误时重新订阅,目前我用的就是这种方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private void registerEvent() {
addSubscribe(RxBus.getDefault().toFlowable(NightModeEvent.class)
.compose(RxUtil.<NightModeEvent>rxSchedulerHelper())
.map(new Function<NightModeEvent, Boolean>() {
@Override
public Boolean apply(NightModeEvent nightModeEvent) {
return nightModeEvent.getNightMode();
}
})
.subscribeWith(new CommonSubscriber<Boolean>(mView, "切换模式失败ヽ(≧Д≦)ノ") {
@Override
public void onNext(Boolean aBoolean) {
mView.useNightMode(aBoolean);
}
@Override
public void onError(Throwable e) {
super.onError(e);
registerEvent();
}
})
);
}

onError处调用方法重新订阅了这个事件,虽然效果不错,添加起来也相对简单,但是显然这个方法也无法让人十分满意,没准就忘记加了呢(= ̄ω ̄=)

那么还有其他方法吗?当然有!那就是:放弃RxBus和EventBus
路人:???
这篇文章放弃RxBus,拥抱RxJava:为什么避免使用EventBus/RxBus或许可以为你解惑,RxBus作为RxJava的衍生物,功能没有EventBus强大,并且至今还没有得到官方的支持,JakeWharton也不建议以RxBus的方式来使用RxJava。
我们在创建下一个新项目前,或许真的应该考虑一下是否要引入RxBusEventBus了╮(╯▽╰)╭

声明:本站所有文章均为原创或翻译,遵循署名-非商业性使用-禁止演绎 4.0 国际许可协议,如需转载请确保您对该协议有足够了解,并附上作者名(Est)及原贴地址