Facebook Access Token lost after App Restart - android

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?

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()) {
..............
}
}
});

When the login is successful save access token somewhere. To the database or to the shared preferences. When your app starts check if there is an access token and if is valid.

Related

Can not perform this action after onSaveInstanceState - android

I have an authorization app. In that app user have accessToken and refreshToken. I done something like this, that if user login on other hardware than in real hardware he logs out automatically. Imagine I have phone1 where I logged in. And now I'm logging in phone2. When I authorize my tokens changes. So I check in phone1 if tokens are changed than logout automatically. But sometimes after that logout I'm getting error like this Exception :
java.lang.IllegalStateException: Can not perform this action after
onSaveInstanceState.
Here is where I'm log out when tokens are expired.
Note that is a
Call<RefreshTokenActivation> newToken = apiClient.newToken(supportObjToken);
newToken.enqueue(new Callback<RefreshTokenActivation>() {
#Override
public void onResponse(Call<RefreshTokenActivation> call, Response<RefreshTokenActivation> response) {
if (response.isSuccessful()) {
} else {
if (response.code() == 401) {
//Perform this call if refresh token is expired
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Activity activity = (Activity) context;
MainActivity mainActivity = (MainActivity) activity;
mainActivity.logOut();
}
}, 1000);
}
}
}
If response is 401, that means that my tokens are expired.If tokens are expired, after a second I throw my user to mainActivity.
Here is the code in MainActivity :
public class MainActivity extends AppCompatActivity
implements FragmentChangeListener, TabLayoutLocationInterface {
private ConnectionDetector connectionDetector;
private SlidePageTabsMainFragment slidePageTabsMainFragment;
private MainFragment mainFragment;
private RelativeLayout logOut;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferencesManager.init(this);
setContentView(R.layout.activity_main);
logOut = (RelativeLayout) findViewById(R.id.list6);
connectionDetector = new ConnectionDetector(this);
slidePageTabsMainFragment = new SlidePageTabsMainFragment();
mainFragment = new MainFragment();
connectionEnable();
userLogOut();
}
public void connectionEnable() {
if (!connectionDetector.isConnected()) {
Toast.makeText(this, "Please check your Internet", Toast.LENGTH_LONG).show();
} else {
Boolean loggedIn = SharedPreferencesManager.getInstance().getUserLogged();
if (loggedIn) {
this.replaceFragment(slidePageTabsMainFragment, true);
} else {
this.replaceFragment(mainFragment, true);
}
}
}
#Override
public void replaceFragment(BaseFragment fragment, Boolean isAddToBackStack) {
String backStateName = fragment.getFragmentName();
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.main_fragment_container, fragment, backStateName);
transaction.addToBackStack(backStateName);
transaction.commit();
}
#Override
public int getTabLayoutLocation() {
SlidePageTabsMainFragment slidePageTabsMainFragment = (SlidePageTabsMainFragment)
getSupportFragmentManager().findFragmentByTag("SlidePageTabsMainFragment");
if (slidePageTabsMainFragment == null) {
return 0;
}
return slidePageTabsMainFragment.getTabLayoutLocation();
}
//If user click logOut button
public void userLogOut() {
logOut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferencesManager.getInstance().setUserLogin(false);
SharedPreferencesManager.getInstance().removeUser();
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
replaceFragment(mainFragment, false);
}
});
}
//A function for automatic logOut
public void logOut() {
SharedPreferencesManager.getInstance().setUserLogin(false);
replaceFragment(new MainFragment(), false);
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
recreate();
SharedPreferencesManager.getInstance().removeUser();
}
#Override
protected void onResume() {
super.onResume();
Log.d("Test", "Text");
}
}
I think there is no something hard. So I getting this exception in transaction.commit();
line in replaceFragment() method in MainActivity. In that call you see I'm calling mainActivity.logOut(); and you see in MainActivity the logOut function.
//A function for automatic logOut
public void logOut() {
SharedPreferencesManager.getInstance().setUserLogin(false);
replaceFragment(new MainFragment(), false);
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
recreate();
}
So in this method I change the SharedPreferences value (that I need for checking on application open does user logged in or not?). After that I'm replacing fragment into mainFragment(that's the base fragment and yes I working on fragments). After that I pop all fragments because after logout if I will click back button, it will go back, so after popping I recreate the app. After recreates it feels like app opened first time. Ok so why it throws exception like this? Any idea?
Used transaction.commitAllowingStateLoss(); instead of transaction.commit();
If you do this than your final state in not allow saved but it is ok if you don't care
For more clarification about commit() and commitAllowingStateLoss() read this blog.

Facebook FriendPickerFragment showing no friends

Any idea why the list might be empty?
The code is below.
public class PickFBFriendsActivity extends FragmentActivity {
FriendPickerFragment friendPickerFragment;
// A helper to simplify life for callers who want to populate a Bundle with the necessary
// parameters. A more sophisticated Activity might define its own set of parameters; our needs
// are simple, so we just populate what we want to pass to the FriendPickerFragment.
public static void populateParameters(Intent intent, String userId, boolean multiSelect, boolean showTitleBar) {
intent.putExtra(FriendPickerFragment.USER_ID_BUNDLE_KEY, userId);
intent.putExtra(FriendPickerFragment.MULTI_SELECT_BUNDLE_KEY, multiSelect);
intent.putExtra(FriendPickerFragment.SHOW_TITLE_BAR_BUNDLE_KEY, showTitleBar);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pick_friends_activity);
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState == null) {
// First time through, we create our fragment programmatically.
final Bundle args = getIntent().getExtras();
friendPickerFragment = new FriendPickerFragment(args);
friendPickerFragment.setUserId(null);
fm.beginTransaction()
.add(R.id.friend_picker_fragment, friendPickerFragment)
.commit();
} else {
// Subsequent times, our fragment is recreated by the framework and already has saved and
// restored its state, so we don't need to specify args again. (In fact, this might be
// incorrect if the fragment was modified programmatically since it was created.)
friendPickerFragment = (FriendPickerFragment) fm.findFragmentById(R.id.friend_picker_fragment);
}
friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
#Override
public void onError(PickerFragment<?> fragment, FacebookException error) {
PickFBFriendsActivity.this.onError(error);
}
});
friendPickerFragment.setOnDoneButtonClickedListener(new PickerFragment.OnDoneButtonClickedListener() {
#Override
public void onDoneButtonClicked(PickerFragment<?> fragment) {
setResult(RESULT_OK, null);
finish();
}
});
}
private void onError(Exception error) {
String text = getString(R.string.exception, error.getMessage());
Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
toast.show();
}
#Override
protected void onStart() {
super.onStart();
}
}
Note that it's pretty much the same as the sample one.
Figured it out: my onStart() method was incomplete, missing the following line:
friendPickerFragment.loadData(false);
Must have deleted it accidently.

Facebook Android SDK: why is the Activity recreated before calling Fragment's onActivityResult?

I wrote a Fragment to manage Facebook log in/out with Facebook Android SDK 3.5.2, following the example given here.
When the login process through Facebook web widgets is done, MainActivity is started again (onCreate is called).
Then in the example code if savedInstanceState!=null in MainActivity's onCreate, the savedInstanceState is checked to know if the existing FacebookPrefsFragment instance must be restored or if a new instance must be created:
if (savedInstanceState == null) {
// Add the fragment on initial activity setup
mainFragment = new MainFragment();
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, mainFragment)
.commit();
} else {
// Or set the fragment from restored state info
mainFragment = (MainFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
}
My problem is that my MainActivity has many Fragments, and savedInstanceState can be not null not only when on the Facebook login process. So I have two questions:
Why is MainActivity created again after the Facebook login process? Shouldn't just FacebookPrefsFragment's onActivityResult be called?
If it's going to be created, how can I know that it is because the Facebook SDK called it?
MainActivity
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
// If the Activity has been started after the Facebook login process, restart the FacebookPrefsFragment,
// but how can I be sure that MainActivity has been called by the Facebook app?
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment facebookPrefsFragment = new FacebookPrefsFragment();
fragmentTransaction.replace(R.id.content_container, facebookPrefsFragment, "facebookPrefsFragment");
fragmentTransaction.commit();
}
else{
// start other Fragment
}
}
// ...
}
FacebookPrefsFragment
public class FacebookPrefsFragment extends Fragment{
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
Log.i(this.getClass().getSimpleName(), "Logged in", MyApplication.LOG_LEVEL);
} else if (state.isClosed()) {
Log.i(this.getClass().getSimpleName(), "Logged out", MyApplication.LOG_LEVEL);
}
}
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
private UiLifecycleHelper uiHelper;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.facebook_prefs, container, false);
LoginButton authButton = (LoginButton) view.findViewById(R.id.authButton);
authButton.setPublishPermissions(Arrays.asList("publish_actions"));
authButton.setFragment(this);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(getActivity(), callback);
uiHelper.onCreate(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
Session session = Session.getActiveSession();
if (session != null &&
(session.isOpened() || session.isClosed()) ) {
onSessionStateChange(session, session.getState(), null);
}
uiHelper.onResume();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
}
This post is a little dated but I figured I'd leave this here incase anyone comes across the issue I faced. When the native Facebook app was not installed my app was being recreated and callbackManager.onActivityResult() kept returning false even though I had the correct request code and data. I was able to resolve this issue by resetting and recalling the following if the initial call returned false:
facebookButton.registerCallback(callbackManager, Activity.this);
callbackManager.onActivityResult(requestCode, resultCode, data);
You need to play around with the
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
See what is the request code while the application is coming from.
Source: https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/widget/FacebookDialog.java#L210
I tested it a couple of months back, the requestCode is what you can use to identify whether is app is coming back from Facebook or not.
[Edit]
This is an ugly hack, but if requestCode == 64206 then your activity just came back from facebook.
Oops, I found out why the MainActivity is recreated everytime: that's because I have the option "Don't keep activities" activated on my phone! Now I have to find out what to do in that case...

Problems with facebook login for android application

We are using for our android application Facebook SDK version 3.0.1
For Facebook login I used this tutorial :
https://developers.facebook.com/docs/howtos/androidsdk/3.0/login-with-facebook/
Many of my users have problems to get in to our application using Facebook login. Users keep sending me emails about this problems and also I can see in their logs, that they cannot get in.
After clicking on Facebook LoginButton, it goes to Facebook LoginActivity, displays the progress bar and stays there for ever. I don't get any answer from Facebook and don't get any exceptions, exept when the user clicks on back button.
I've printed some logs from Facebook's SDK, so maybe someone will understand why this problems happens.
here is an example of logs flow that works OK
here is my code :
My Activity :
/**My Activity **/
//BackClickListenerActivity extends FragmentActivity
public class RegisterActivity extends BackClickListenerActivity implements RegistrationManager{
private RegistrationFragment mainFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.register);
if (savedInstanceState == null) {
// Add the fragment on initial activity setup
mainFragment = new RegistrationFragment();
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, mainFragment)
.commit();
} else {
// Or set the fragment from restored state info
mainFragment = (RegistrationFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
}
...
}
public void onStart() {
mainFragment.initialize(this,R.layout.register,false);
super.onStart();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_FACEBOOK_LOGIN:
if (resultCode == RESULT_OK) {
...
}
else {
...
}
...
}
}
}
My Fragment :
public class RegistrationFragment extends Fragment{
public void initialize(RegistrationManager registrationManager, int layoutRes, boolean hideButton){
this.registrationManager = registrationManager;
sentRequest = false;
// I use this fragment from 2 different Activities, and 2 layouts
this.layoutRes = layoutRes;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG,"onCreateView RegistrationManager");
final View view = inflater.inflate(layoutRes, container, false);
LoginButton authButton = (LoginButton) view.findViewById(R.id.facebook_login);
authButton.setFragment(this);
authButton.setReadPermissions(Arrays.asList(FacebookConfig.getInstance().getPermissions()));
...
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"onCreate RegistrationManager");
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(getActivity(), callback);
uiHelper.onCreate(savedInstanceState);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if(state == SessionState.OPENING){
...
}
else if (state.isOpened()) {
...
} else if (state.isClosed()) {
...
}
}
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onStop(){
super.onStop();
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
}
At the SDK, I did some changes that are dealing with the LoginButton - I've changed the image, the text and put under comment at onClick listener the case when session is not null (to prevent logout).
Hope my question is clear enough, and someone could help us.
Thank you,
Alex
I have the same problem. In devices 2.3.4 or lower default login don't work as expected. For all those devices I have to implement Web Dialog. Getting access token from the dialog after completion and setting up session from that access token. It seems to be working as of now.
Bundle bundle = new Bundle();
bundle.putString("message", "message");
WebDialog localWebDialog = new WebDialog.Builder(this, "app_id", "oauth", bundle).build();
localWebDialog.setOnCompleteListener(new WebDialog.OnCompleteListener()
{
public void onComplete(Bundle bundle, FacebookException facebookException)
{
Session.getActiveSession();
AccessToken localAccessToken = AccessToken.createFromExistingAccessToken(bundle.getString("access_token"), null, null, AccessTokenSource.WEB_VIEW, null);
Session.openActiveSessionWithAccessToken(MainActivity.this.getApplicationContext(), localAccessToken, MainActivity.this.callback);
}
});
localWebDialog.show();
private class SessionStatusCallback implements Session.StatusCallback {
#Override
public void call(Session session, SessionState state, Exception exception) {
if(session.isOpened()
//do something
}
I cant add a comment, so please dont Downvote this :).
In order to Facebook you dont get an exceptions but often a warning/logoutputs, in there you can see what happens during the login process. If you would have a keyhash problem, then you would definetely get an warning exception.
Please check your logcat for hints.
A very good sample is this Hackbook

Why does the order in which fragments are added via the SupportFragmentManger matter?

I am in the process of creating an AuthenticationActivity which will provide users the option of logging in via Facebook, Twitter or app specific auth. After following the well written tutorial Use Facebook Login from the Facebook Android SDK documentation I had Facebook authentication working.
Unfortunately, when I proceeded to add a Twitter Fragment to provide similar login functionality I ran into issues. Suddenly the Facebook login button would not change state and my authentication to Facebook would not fully complete, though I could see authentication callbacks being returned.
After going round and round I finally decided to change the order that the AuthenticationActivity adds fragments via the SupportFragmentManager. When I did Facebook started working again, but then Twitter fragment broke.
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, twitterFragment)
.add(android.R.id.content, facebookFragment)
.commit();
Rather than make me feel better this made me feel worse. I admit to not fully understanding fragments, but am totally puzzled as to why the order in which the fragments are added has this affect. Which ever comes first does not work, but the one added second does. It may be important to note that I am utilizing actionbarsherlock and its fragment implementation.
Below you will find my activity and fragment code
AuthenticationActivity
public class AuthenticationActivity extends SherlockFragmentActivity {
private FacebookFragment facebookFragment;
private TwitterFragment twitterFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
addFragments();
} else {
restoreFragments();
}
}
private void addFragments() {
facebookFragment = new FacebookFragment();
twitterFragment = new TwitterFragment();
// TODO the order of this MATTERS if Facebook isn't last
// Facebook auth breaks and vice versa.
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, twitterFragment)
.add(android.R.id.content, facebookFragment)
.commit();
}
private void restoreFragments() {
facebookFragment = (FacebookFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
twitterFragment = (TwitterFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
}
}
Facebook Fragment (largely based on SDK documentation example)
public class FacebookFragment extends SherlockFragment {
private UiLifecycleHelper uiHelper;
private static final String TAG = FacebookFragment.class.getSimpleName();
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state,
Exception exception) {
onSessionStateChange(session, state, exception);
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.authentication, container, false);
LoginButton facebookButton
= (LoginButton) view.findViewById(R.id.facebookButton);
facebookButton.setFragment(this);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(getActivity(), callback);
uiHelper.onCreate(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
Session session = Session.getActiveSession();
if (session != null && (session.isOpened() || session.isClosed())) {
onSessionStateChange(session, session.getState(), null);
}
uiHelper.onResume();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
if (state.isOpened()) {
Log.i(TAG, "Logged in...");
} else if (state.isClosed()) {
Log.i(TAG, "Logged out...");
} else {
Log.i(TAG, "unknown state " + state);
}
}
}
TwitterFragment
public class TwitterFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.authentication, container, false);
Button twitterButton = (Button) view.findViewById(R.id.twitterButton);
twitterButton.setOnClickListener(twitterClickListener);
return view;
}
private OnClickListener twitterClickListener = new OnClickListener() {
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, TwitterLoginActivity.class);
context.startActivity(intent);
}
};
}
Why does the order in which the above fragments are added via the SupportFragmentManger matter?
private void restoreFragments() {
facebookFragment = (FacebookFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
twitterFragment = (TwitterFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
}
You need to assign each fragment a different id otherwise you will always get the same fragment for a given id. I guess you'd get the first declared/added fragment but that depends in the implementation. (You probably are getting a class cast exception).
To fix this, assign them different ids and add them to different placeholders.
.beginTransaction()
.add(R.id.twitter_fragment, twitterFragment)
.add(R.id.facebook_fragment, facebookFragment)
.commit();
This requires other changes as well but hopefully you can get there.

Categories

Resources