Распространение Observables в onDettachView
Я сталкиваюсь с известной проблемой IllegalStateException в моем приложении. Проблема связана с выполнением сетевого запроса (с использованием Retrofit), возвращающего мне Observable. Я использую отличный фреймворк Mosby для работы с MVP, вот мой код:
public class CarAdPresenterCustomer extends CarAdPresenterAbstract {
private final GetCarByIdUseCase getCarByIdUseCase;
private final GetCarMatchDetailsUseCase getCarMatchDetailsUseCaseUseCase;
public CarAdPresenterCustomer(GetCarByIdUseCase getCarByIdUseCase, GetCarMatchDetailsUseCase getCarMatchDetailsUseCaseUseCase) {
this.getCarByIdUseCase = getCarByIdUseCase;
this.getCarMatchDetailsUseCaseUseCase = getCarMatchDetailsUseCaseUseCase;
}
public void getCarMatchDetails(String carId) {
if (isViewAttached()) {
getView().showLoading();
}
getCarMatchDetailsUseCaseUseCase.execute(new GetCarMatchDetailsSubscriber(), new GetCarMatchDetailsUseCase.Params(carId));
}
public void getCarDetails(String carId) {
getCarByIdUseCase.execute(new GetCarByIdSubscriber(), new GetCarByIdUseCase.Params(carId));
}
@Override
public void detachView(boolean retainInstance) {
getCarByIdUseCase.dispose();
getCarMatchDetailsUseCaseUseCase.dispose();
super.detachView(retainInstance);
}
private class GetCarByIdSubscriber extends DefaultObserver<DefaultCarResponse> {
@Override
public void onNext(DefaultCarResponse carResponse) {
if (carResponse != null) {
if (isViewAttached()) {
getView().hideLoading();
getView().inflateCarUiComponents(carResponse.getCar());
}
}
}
@Override
public void onError(Throwable exception) {
if (isViewAttached()) {
getView().hideLoading();
getView().showErrorMessage(exception.getMessage());
}
}
}
Исключение, которое я получаю от Crashlytics:
Fatal Exception: java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6843)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1884)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1902)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)
at br.com.moobie.android.emailConfirmation.ui.fragment.EmailConfirmationFragment.showEmailConfirmationError(EmailConfirmationFragment.java:202)
at br.com.moobie.android.emailConfirmation.presenter.EmailConfirmationPresenterImpl$GetUserSubscriber.onNext(EmailConfirmationPresenterImpl.java:75)
at br.com.moobie.android.emailConfirmation.presenter.EmailConfirmationPresenterImpl$GetUserSubscriber.onNext(EmailConfirmationPresenterImpl.java:63)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:200)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:252)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6843)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Мои вопросы: правильно ли располагать Observables в методе detachView? Насколько я понимаю, detachView вызывается при вызове фрагмента (я использую его с фрагами) onDestroyView сразу после onStop (где состояние проверяется Android). Если нет, должен ли я создать метод dispose в моем докладчике и вызвать его из моего фрагмента onStop?
Спасибо!
1 ответ
Я думаю detachView()
является правильным событием, если вы располагаете на onStop()
- где бы ваша деятельность не остановилась, запрос будет отменен. с точки зрения UX, это означает, что если пользователь запустил запрос, затем получил телефонный звонок или переключился на другое приложение и вернулся, запрос не будет продолжен, и он должен снова запустить его и подождать внутри приложения.
что касается этой проблемы, даже если бы вы располагали onStop()
, это не решит проблему, так как onSaveInstanceState()
называется раньше onStop()
,
Это общая распространенная проблема фрагментов, когда вы фиксируете транзакцию фрагмента после onSaveInstance()
и должны быть решены на уровне фрагментов, вы можете увидеть здесь различные решения, такие как использование commitAllowingStateLoss()
например:
IllegalStateException: не может выполнить это действие после onSaveInstanceState с ViewPager