Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Facebook SDK 3.0 callback fires twice

I have the following activity and I am using Facebook's LoginButton. onSessionStateChange is being called multiple times. I have an asynctask that I want to run after a successful login that also opens a new activity once complete. Right now this starts multiple async tasks. How can I find the final state so it will not fire twice? Ive looked through all of the examples and Facebook says that session.isOpened() should work, but its still firing multiple times.

UPDATE:

After removing the session code from onResume it only gets called once but according to https://developers.facebook.com/docs/howtos/androidsdk/3.0/login-with-facebook/#step3 I need that code in OnResume for certain situations.

public class LoginActivity extends SherlockActivity {

private static final String TAG = "LoginActivity";

private Context context;
private int statusCode;
private String emailAddress = null;
private String password = null;
private GraphUser fbUser;

private UiLifecycleHelper uiHelper;

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state,
            Exception exception) {
        onSessionStateChange(session, state, exception);
    }
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    context = getApplicationContext();

    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);

    final LoginButton fbBtn = (LoginButton) findViewById(R.id.facebook_login);
    fbBtn.setReadPermissions(Arrays.asList("basic_info", "email"));
    /*
     * fbBtn.setOnClickListener(new View.OnClickListener() {
     * 
     * @Override public void onClick(View v) {
     * 
     * Intent intent = new Intent(context, MainActivity.class);
     * startActivity(intent);
     * 
     * finish();
     * 
     * } });
     */
}

@Override
protected void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}

@Override
protected void onResume() {
    super.onResume();

    // For scenarios where the main activity is launched and user
    // session is not null, the session state change notification
    // may not be triggered. Trigger it if it's open/closed.
    Session session = Session.getActiveSession();
    if (session != null && (session.isOpened() || session.isClosed())) {
        onSessionStateChange(session, session.getState(), null);
    }
    uiHelper.onResume();
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Log.d("FbLogin", "Result Code is - " + resultCode +"");
    uiHelper.onActivityResult(requestCode, resultCode, data);

}

private void onSessionStateChange(Session session, SessionState state,
        Exception exception) {
    if (session != null && session.isOpened()) {
        Log.i(TAG, "Logged in...");
        Log.i(TAG, "Access Token" + session.getAccessToken());

        if (state == SessionState.OPENED) {
        Request.executeMeRequestAsync(session,
                new Request.GraphUserCallback() {
                    @Override
                    public void onCompleted(GraphUser user,
                            Response response) {
                        if (user != null) {
                            Log.i(TAG, "User ID " + user.getId());
                            Log.i(TAG, "Email " + user.asMap().get("email"));

                            fbUser = user;

                            //FbRegisterTask fbReg = new FbRegisterTask(LoginActivity.this, user);
                            //fbReg.execute();
                            //finish();
                        }
                    }
                });
        }

    } else if (session.isClosed()) {
        Log.i(TAG, "Logged out...");
    }
}
}
like image 819
nawlrus Avatar asked Jun 09 '13 18:06

nawlrus


1 Answers

I had the same issue.

One call is coming from UiLifecycleHelper when it invokes the callback:

UiLifecycleHelper callback
onSessionStateChange()

The other comes from Activity resuming the LoginFragment.

LoginActivity.onResumeFragments()
LoginFragment.onResume()
onSessionStateChange()

In many cases, this is fine, but in your case it's obviously a problem due to the AsyncTask.

You can cache the session received in onSessionStateChange() and see if its state and tokenInfo changed, and only then invoke your async task. Checking the combination of session state and tokenInfo should suffice:

private void onSessionStateChange(Session session, SessionState state, Exception exception) {
    if (state.isOpened()) {
        if (mSession == null || isSessionChanged(session)) {
            mSession = session;
            LogUtils.LOGFB(TAG, "Logged in using facebook");
            LogUtils.LOGFB(TAG, "Access Token: " + session.getAccessToken());
            // Run your AsyncTask
        }

    } else if (state.isClosed()) {
        LogUtils.LOGFB(TAG, "Logged out from facebook");
        // Display your non-authenticated UI
    }
}

private boolean isSessionChanged(Session session) {

    // Check if session state changed
    if (mSession.getState() != session.getState())
        return true;

    // Check if accessToken changed
    if (mSession.getAccessToken() != null) {
        if (!mSession.getAccessToken().equals(session.getAccessToken()))
            return true;
    }
    else if (session.getAccessToken() != null) {
        return true;
    }

    // Nothing changed
    return false;
}
like image 184
Eduard Avatar answered Oct 27 '22 14:10

Eduard