1

I am trying to develop an app using Mosby and EventBus. First event I want to have is after user login, creating a sticky event so every screen can access Login info at all times.

Based off the Mosby mail sample, I have a BasePresenter like this:

public abstract class EventBusPresenter<V extends MvpView> extends MvpBasePresenter<V> {


    private static final java.lang.String TAG = tag(EventBusPresenter.class);
    @Inject
    protected EventBus mEventBus;


    LoginSuccessfulEvent userInfo;

    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onLoginSuccessful(LoginSuccessfulEvent event) {
        MCLog.i(TAG, "Received a login event!");
        userInfo = event;
        onLoginReceived(event);
    }

    protected abstract void onLoginReceived(LoginSuccessfulEvent e);

    public LoginSuccessfulEvent getUserInfo(){
        return userInfo;
    }


    @Override
    public void attachView(V view) {
        super.attachView(view);
        mEventBus.register(this);

    }

    @Override
    public void detachView(boolean retainInstance) {
        super.detachView(retainInstance);
        mEventBus.unregister(this);
    }
}

When the user logins I use this code:

public void doLogin(String username, String password) {
    if (isViewAttached()) {
        getView().showLoading();
    }

    cancelSubscription();
    mSubscriber = new Subscriber<AuthenticationResponse>() {

        @Override
        public void onCompleted() {
            if (isViewAttached()) {
                getView().loginSuccessful();
            }
        }

        @Override
        public void onError(Throwable e) {
            if (isViewAttached()) {
                getView().showLoginError();
            }
        }

        @Override
        public void onNext(AuthenticationResponse authenticationResponse) {
            User user = authenticationResponse.getUser();
            MCLog.w(TAG, String.format("Login was successful with user: %s", user) );
            mEventBus.postSticky(new LoginSuccessfulEvent(user, authenticationResponse.getToken()));
            String token = authenticationResponse.getToken();
            MCLog.i(TAG, String.format("Token obtained = %s", token));
            mSharedPreferences.edit().putString(PreferenceKeys.TOKEN_KEY, token).apply();


        }
    };

My idea is that for every screen, as soon as its loaded it can retrieve the UserInfo through the EventBus subscription.

The issue is -- this event arrives too son. As per mosby's own BaseFragment class I do this:

public abstract class BaseFragment<V extends MvpView, P extends MvpPresenter<V>> extends MvpFragment<V, P> {

    private Unbinder mUnbinder;

    @LayoutRes
    protected abstract int getLayoutRes();

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(getLayoutRes(), container, false);
    }


    @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        inject();
        super.onViewCreated(view, savedInstanceState);
        mUnbinder = ButterKnife.bind(this, view);
    }

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

    /**
     * Inject dependencies
     */
    protected void inject() {

    }


}

This means that injection arrives before the views are created, so whenever I try to respond to a LoginEvent being received, the UI elements that need updating are not there anymore.

How can I achieve this? Is this even the right way to do it?

M Rajoy
  • 4,028
  • 14
  • 54
  • 111

1 Answers1

0

Do mUnbinder = ButterKnife.bind(this, view); either in onCreateView() or if you prefer to do that in onViewCreated() the call mUnbinder = ButterKnife.bind(this, view); before calling super.onViewCreated().

Btw. Using an EventBus for that sounds painful. Why not simply having a class like UserMananger where you can get the current authenticated user or null if user is not authenticated. Also, since you are using RxJava it would make sense to include the UserManager in your RxJava chain / stream on each screen.

sockeqwe
  • 15,574
  • 24
  • 88
  • 144
  • Thanks, can you expand on the last part? Including UserManager in my RxJava chain? I did eventually create a UserManager so Im curious about this. – M Rajoy Nov 22 '16 at 13:30