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.
Related
I am using drawerlayout to allow the user to open different questionnaires. The questions in the questionnaire are different fragments. The problem is that when a questionnaire is started and say the use goes to question no. 5 and exits the app then she or he will have to start from the home page ie first fragment in the drawer layout. How do I save the last fragment ie question shown so that I can show it again when the app is reopened?
Below is the code in one of the fragments that do not open up if the user taps the Home button.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { \\ handle view related code and triggering other functions }
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
cardContext = context;
if (context instanceof OnShoppingDoneListener) {
onShoppingDoneListener = (OnShoppingDoneListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onResume() {
super.onResume();
bundle = getArguments();
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onDetach() {
super.onDetach();
onShoppingDoneListener = null;
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("cartContent", selectionItemArrayList);
}
And here is the relevant code Main Activity where I open that particular fragment:
public class MainActivity extends AppCompatActivity implements
OnRestaurantSelect {
public void onRestaurantSelect(Bundle bundle){
boolean direction = bundle.getBoolean("direction");
if (direction) {
MenuCardFragment fragment = new MenuCardFragment();
openFragment(bundle, fragment, true);
} else {
AddressFragment fragment = new AddressFragment();
openFragment(bundle, fragment, false);
}
}
private void openFragment(Bundle bundle, Fragment fragment, Boolean direction) {
// Passing the pickup or delivery option + address + schedule + restaurant + order details + payment
fragment.setArguments(bundle);
//Starting fragment with animation
if (direction) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_right).replace(R.id.frame_container, fragment, null);
fragmentTransaction.commit();
} else {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_left).replace(R.id.frame_container, fragment, null);
fragmentTransaction.commit();
}
}
Design a key for each fragment, when the app exits, save that key in a SharedPreference, than when the app restart, get that SharedP and open that fragment
My app uses a Navigation Drawer with several menu items which basically opens different Fragments. Each fragments may run an AsyncTask that shows Toast message afterwards. However, when the user tries to open a fragment while another fragment is running, I get a nullpointer error which is understandable since the original fragment has been detached.
However, is it possible to have the Toast show even then? I basically has this code when an item is clicked on the navigator.
public void setFragment(Fragment fragment) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content, fragment)
.commit();
}
Then on the fragment is just a simple asynctask that shows a Toast message onPostExecute.
Toast.makeText(getContext(), t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
Appreciate any help.
UPDATE (03/28/2018)
I tried using listener and it seems to work.
I basically have a BaseFragment in which all my fragments extends. I just added a callback in it.
public class BaseFragment extends Fragment {
private OnToast callback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
callback = (BaseFragment.OnToast) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnAuthenticateListener");
}
}
public OnToast getCallback() {
return callback;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
}
public interface OnToast {
void toast(String message);
}
}
In my actual fragment, I have:
public class JailsFragment extends BaseFragment {
private List<Jail> jailList = new ArrayList<>();
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setTitle("Jails");
setAdapter(new JailAdapter());
if (savedInstanceState == null) {
onSwipeRefresh();
}
}
#Override
public void onSwipeRefresh() {
super.onSwipeRefresh();
setRefreshing(true);
jailList.clear();
FreeNAS.getInstance().getJails().getJails(new Callback<List<Jail>>() {
#Override
public void onResponse(Call<List<Jail>> call, Response<List<Jail>> response) {
if (response.code() == 200) {
jailList.addAll(response.body());
notifyDatasetChanged();
} else {
//Toast.makeText(getContext(), response.message(), Toast.LENGTH_LONG).show();
getCallback().toast(response.message());
}
setRefreshing(false);
}
#Override
public void onFailure(Call<List<Jail>> call, Throwable t) {
//Toast.makeText(getContext(), t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
getCallback().toast(t.getLocalizedMessage());
setRefreshing(false);
}
});
}
}
Then in my MainActivity:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, BaseFragment.OnToast {
private SharedPreferences pref;
private Toolbar toolbar;
private DrawerLayout drawer;
private ActionBarDrawerToggle toggle;
private NavigationView navigationView;
#Override
public void toast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pref = PreferenceManager.getDefaultSharedPreferences(this);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
if (savedInstanceState == null) {
setFragment(new AuthenticateFragment());
}
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
final int id = item.getItemId();
drawer.closeDrawer(GravityCompat.START);
drawer.postDelayed(new Runnable() {
#Override
public void run() {
if (id == R.id.nav_plugins) {
setFragment(new PluginsFragment());
} else if (id == R.id.nav_jails) {
setFragment(new JailsFragment());
} else if (id == R.id.nav_jails_configuration) {
setFragment(new ConfigurationFragment());
} else if (id == R.id.nav_services) {
setFragment(new ServicesFragment());
} else if (id == R.id.nav_alerts) {
setFragment(new AlertsFragment());
} else if (id == R.id.nav_updates) {
setFragment(new UpdatesFragment());
}
}
}, 300);
return true;
}
public void setFragment(Fragment fragment) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content, fragment)
.commit();
}
}
I assume you are receiving a nullPointer exception here
Toast.makeText(getContext(), t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
I would say that you are receiving the null pointer because you do not have the context anymore.
The possible solution is:
1- Declare you Application as singleton, then you could use MyApplication.getInstance() and use this as a context for the Toast message. Check this link to see how to create this singleton. Also it is recommended to use the applicationContext instead of the activity for toast messages
As far as I understand getContext() and getActivity() will return the same object, which is the activity so that will not help.
EDIT 1:
The problem with the solution you are proposing (having a reference to the Activity, in this case as an interface) is that you may have memory leaks. When I say "may have" is because you are doing something special when you put this line:
setRetainInstance(true);
You may want to read this post.
The memory leak will be generated when you do not need the Activity anymore (let's say you move to another activity) but the fragment (the object) is not being destroyed yet for some reason. Another example is with a low connection to Internet, then the user may leave the screen to move to another one, but your fragment is still alive and so your activity can not be garbage collected. This is why I do not recommend your approach :).
PS: sorry for the late answer, I was on vacation :P.
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.
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.
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.