Search code examples
androidfacebookandroid-fragmentsfacebook-access-tokenfacebook-sdk-4.0

Facebook Access Token lost after App Restart


I'm working with Facebook SDK 4.0 and using the in-built LoginButton. I have a Fragment which contains the LoginButton and another which just contains a TextBox.

Here's a code snippet from the Fragment :

public class LoginFragment extends Fragment {

private OnLoginFragmentInteractionListener mListener;
LoginButton loginButton;
CallbackManager callbackManager;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
    }

    callbackManager = CallbackManager.Factory.create();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_login, container, false);

    loginButton = (LoginButton) view.findViewById(R.id.login_button);

    // If using in a fragment
    loginButton.setFragment(this);

    // Callback registration
    loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            Toast.makeText(getActivity(), "Logged in successfully.", Toast.LENGTH_SHORT).show();
            onLoginEvent(true);
        }
        @Override
        public void onCancel() {
            Toast.makeText(getActivity(), "Login canceled.", Toast.LENGTH_SHORT).show();
            onLoginEvent(false);
        }
        @Override
        public void onError(FacebookException exception) {
            Toast.makeText(getActivity(), "Failed to log in. Please try again.", Toast.LENGTH_SHORT).show();
            onLoginEvent(false);
        }
    });

    return view;
}

public void onLoginEvent(boolean loginSuccess) {
    if (mListener != null) {
        mListener.onLoginFragmentInteraction(loginSuccess);
    }
}

public interface OnLoginFragmentInteractionListener {
    public void onLoginFragmentInteraction(boolean onLoginSuccess);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    callbackManager.onActivityResult(requestCode, resultCode, data);
}
}

The Activity looks something like this :

public class LoginActivity extends ActionBarActivity implements
    LoginFragment.OnLoginFragmentInteractionListener, TestFragment.OnFragmentInteractionListener {

static final String TAG = "LoginActivity";

private LoginFragment loginFragment;
private TestFragment testFragment;
private AccessToken accessToken;
private AccessTokenTracker accessTokenTracker;
private Profile fbProfile;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    FacebookSdk.sdkInitialize(getApplicationContext());

    if (savedInstanceState == null) {
        // Add the fragment on initial activity setup
        Log.d(TAG, "Bundle = null, isLoggedIn() = " + isLoggedIn());
        if (isLoggedIn()) {
            testFragment = new TestFragment();
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, testFragment).commit();
        } else {
            loginFragment = new LoginFragment();
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, loginFragment).commit();
        }
    } else {
        // Or set the fragment from restored state info
        Fragment frag = getSupportFragmentManager()
                .findFragmentById(R.id.fragment_container);
        if (frag instanceof LoginFragment) {
            Log.d(TAG, "Bundle != null, fragment = LoginFragment");
            loginFragment = (LoginFragment) frag;
        }
        else if (frag instanceof TestFragment) {
            Log.d(TAG, "Bundle != null, fragment = TestFragment");
            testFragment = (TestFragment) frag;
        }
    }
}


@Override
public void onLoginFragmentInteraction(boolean loginSuccess) {
    updateUI(loginSuccess);
}

public void updateUI(boolean loggedIn) {
    // User is logged in, show the main fragment
    if (loggedIn) {
        testFragment = new TestFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container, testFragment).commit();
    }
    // User is logged out, show the login fragment
    else {
        loginFragment = new LoginFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container, loginFragment).commit();
    }
}

public boolean isLoggedIn() {
    accessToken = AccessToken.getCurrentAccessToken();
    if (accessToken != null && !accessToken.isExpired())
        return true;
    else
        return false;
}
}

What I want to do is to check if the user has already logged in. If they have, then I show the Test Fragment, otherwise I show the Login Fragment.

So when the user first logs in, I use the interface callback to notify the Activity that the user has logged in and show the TestFragment. Also, if the user goes away from the app and then returns, I check in the onCreate() method if the user is logged in by checking the access token.

When the user first logs in, it works as desired. But the problem I'm facing is that if I kill the app or remove it from the Recents list, I lose the access token. AccessToken.getCurrentAccessToken() always returns null. Is this not the right way to handle it?


Solution

  • As you mention in your comment. You have should checked user logged in when the FacebookSDK finished initialization.
    The problem in your case is that you checked AccessToken when the SDK had not finished initialization yet. To solve this problem checking AcessToken in onInitialized() method of FacebookSdk.InitializeCallback which is called when the SDK has been initialized.

    FacebookSdk.sdkInitialize(getApplicationContext(), new FacebookSdk.InitializeCallback() {
        @Override
        public void onInitialized() {
            if (isLoggedIn()) {
                ..............
            }
        }
    });