question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Call onNext from Main thread dont repect subscribeOn when flatMap or switchMap

See original GitHub issue

Im doing a wrapper for the facebook sdk and trying to do it with rx java but Im getting an issue with the actual thread for the observables created in my wrapper. I want to get the user object after the user log in with fb.

public class LoginPresenter extends BasePresenter<LoginView> {

public void startFacebookLogin() {
    if (!mNetworkChecker.isNetworkConnectionAvailable()) {
      mView.showNoConnectionError();
      return;
    }

    Subscription subscription = mFacebookRepository.startLoginFlow()
        .flatMap(loginResult -> mFacebookRepository.getUser())
        .compose(Transformer.applyIoSchedulers())
        .subscribe(user -> mView.startSignUpView(user), this::manageErrorFlow);

    mCompositeSubscription.add(subscription);
  }
}
public class FacebookRepository {

  private WeakReference<Activity> mActivityWeakReference;
  @Nullable private CallbackManager callbackManager;

  public FacebookRepository(String facebookPublicKey, Activity activity) {
    if (!FacebookSdk.isInitialized()) {
      FacebookSdk.sdkInitialize(com.barista_v.wapa.api.Api.getContext());
    }

    if (com.barista_v.wapa.api.Api.getLogLevel() > com.barista_v.wapa.api.Api.LOG_LEVEL_BASIC) {
      FacebookSdk.addLoggingBehavior(LoggingBehavior.REQUESTS);
    }

    mActivityWeakReference = new WeakReference<>(activity);

    FacebookSdk.setApplicationId(facebookPublicKey);
  }

  public Observable<LoginResult> startLoginFlow() {
    return Observable.create(subscriber -> {
      Activity activity = mActivityWeakReference.get();
      if (activity != null) {
        LoginManager loginManager = LoginManager.getInstance();
        callbackManager = CallbackManager.Factory.create();

        loginManager.logInWithReadPermissions(activity, getPermissions());
        loginManager.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
          @Override
          public void onSuccess(LoginResult loginResult) {
            subscriber.onNext(loginResult);
            subscriber.onCompleted();
          }

          @Override
          public void onCancel() {
            subscriber.onError(
                new FacebookLoginCancelException("Login canceled.", "Facebook Error", null));
          }

          @Override
          public void onError(FacebookException exception) {
            subscriber.onError(new FacebookLoginException(exception));
          }
        });
      } else {
        Timber.w("The activity reference is null for FacebookRepository.startLoginFlow()");
        subscriber.onError(
            new FacebookLoginException("Something happened internally.", "Facebook Error", null));
      }
    });
  }

  public Observable<User> getUser() {
    return Observable.defer(() -> {
      AccessToken accessToken = AccessToken.getCurrentAccessToken();
      String userId = accessToken.getUserId();
      Bundle params = new Bundle();
      params.putString("fields", "name,email");
      String graphPath = "/" + userId;
      GraphRequest graphRequest = new GraphRequest(accessToken, graphPath, params, HttpMethod.GET);

      JSONObject json;
      try {
        GraphResponse result = graphRequest.executeAndWait();
        json = result.getJSONObject();
      } catch (FacebookException e) {
        return Observable.error(e);
      }

      String name, email;

      try {
        name = json.getString("name");
      } catch (JSONException | JsonSyntaxException | NullPointerException e) {
        return Observable.error(e);
      }

      try {
        email = json.getString("email");
      } catch (JSONException | JsonSyntaxException | NullPointerException e) {
        com.barista_v.wapa.api.error_handling.ApiException exception =
            new UserInfoMissingException(
                "Email access permission is not granted but it is required.",
                "Invalid Facebook Permissions", e);
        return Observable.error(exception);
      }

      String photoUrl =
          String.format("https://graph.facebook.com/%s/picture?type=large", userId);

      return Observable.just(new User(name, email, photoUrl));
    });
  }

  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (callbackManager != null) {
      callbackManager.onActivityResult(requestCode, resultCode, data);
    }
  }
}

public class Transformer {
  public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
    return observable -> observable.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());
  }
}

The problem is that the code that execute the mFacebookRepository.getUser() is in the main thread. Should not be the IO thread?

I create the observable and call onNext when FacebookCallback call onSuccess function and it is called in the main thread, so subscriber.onNext is called on the main thread.

Is this a bug or something Im doing wrong?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:1
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
akarnokdcommented, Jan 5, 2016
Subscription subscription = mFacebookRepository.startLoginFlow()
        .flatMap(loginResult -> mFacebookRepository.getUser().subscribeOn(Schedulers.io())
        .compose(Transformer.applyIoSchedulers())
        .subscribe(user -> mView.startSignUpView(user), this::manageErrorFlow);
1reaction
akarnokdcommented, Jan 5, 2016

No, streams can go around on pretty much any scheduler or even external threads. The only thing that can be done is apply subscribeOn and observeOn at questionable points to make sure the stream runs on the required threads.

Read more comments on GitHub >

github_iconTop Results From Across the Web

RxJava — emit on subscribeOn() thread - Stack Overflow
The observeOn-subscriber will get called from the main-thread. The observeOn-subscriber re-directs onSuccess downstream-call (e.g. flatMap) ...
Read more >
Observable (RxJava Javadoc 3.1.5) - ReactiveX
Subscribes to the ObservableSource and calls a Predicate for each item of the current Observable , on its emission thread, until the predicate...
Read more >
Flux (reactor-core 3.5.0)
A Reactive Streams Publisher with rx operators that emits 0 to N elements, and then completes (successfully or with an error).
Read more >
Understanding RxJava subscribeOn and observeOn
RxJava Schedulers. Threading in RxJava is done with help of Schedulers. Scheduler can be thought of as a thread pool managing 1 or...
Read more >
Reactive Programming in Java
The basic idea behind reactive programming is that there are certain ... Then he calls onNext() on Mover 3, the final Subscriber who...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found