Tuesday, December 13, 2016

Presenter callback in the middle of rotation


This is my answer to this question.

First of all I use this cool method to keep presenter alive even if activity recreated: Presenter surviving orientation changes with Loaders. It detaches and attaches activity in onStop and onStart.
Need to mention also, that your second choice with persistent fragment in widely used, e.g. by Fernando Cejas. I've learned clean architecture approach with his articlesand he uses setRetainState(true).
And still your question is driving me crazy as well. Only solution I've found so far is ugly as hell. But it should work. Idea: after work done, I check if view is attached. If so, I proceed normally. I there is no view, that we are in the middle of rotation. So I have flag, that indicate, that work is done. I turn it on. Also I cache any needed data. And wait for the next view attaching. Where I check that flag.
Here is my code snippet. I'm not proud of it thought.
class SplashPresenter extends BasePresenter<SplashView> {

    private final SplashInteractor splashInteractor;
    private boolean isSplashWorkStarted;
    private boolean isSplashWorkFinished;
    private boolean isSplashWorkError;
    private Throwable splashWorkError;

    @Inject
    SplashPresenter(SplashInteractor splashInteractor) {
        this.splashInteractor = splashInteractor;
    }

    @Override
    public void attachView(SplashView mvpView) {
        super.attachView(mvpView);
        if (isSplashWorkFinished) {
            getMvpView().showApplicationUi();
        } else if (isSplashWorkError) {
            getMvpView().showError(splashWorkError.getMessage());
        }
    }

    void executeSplashWork() {
        if (!isSplashWorkStarted) {
            splashInteractor.execute(new SplashInteractorSubscriber());
            isSplashWorkStarted = true;
        }
    }

    @Override
    public void onDestroyed() {
        splashInteractor.unsubscribe();
    }

    private final class SplashInteractorSubscriber extends Subscriber<Void> {
        @Override
        public void onCompleted() {
            if (isViewAttached()) {
                getMvpView().showApplicationUi();
            } else {
                isSplashWorkFinished = true;
            }
        }

        @Override
        public void onError(Throwable e) {
            if (isViewAttached()) {
                getMvpView().showError(e.getMessage());
            } else {
                isSplashWorkError = true;
                splashWorkError = e;
            }
        }

        @Override
        public void onNext(Void v) {
        }
    }
}

No comments:

Post a Comment