I am relatively new to the android Facebook SDK and need help setting up my login activity after spending fruitless days on this. I am unable to resolve the issues and each time I try and import com.facebook.Session (as recommended in the tutorial, it is automatically changed to "SessionState" instead, which again doesn't help resolve the errors. Please can someone help me fix this.
I am using facebook sdk v3.6 and the latest ADT and SDK tools. Also, my facebook SDK is in a different folder (with the android SDK) and the project exists in a seperate workspace (again, as recommeneded by the tutorial, I did not choose to copy the fb sdk into my workspace, simply imported it). All the FB samples are working fine, I tried copying the code from Scrumptious's main activity to get my login working.
Here's the code for reference:
package com.example.myproject;
import android.content.Intent;
import android.os.Bundle;
import android.service.textservice.SpellCheckerService.Session;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;
import com.facebook.AppEventsLogger;
import com.facebook.Session.StatusCallback;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
public class FBLoginActivity extends FragmentActivity {
private static final String USER_SKIPPED_LOGIN_KEY = "user_skipped_login";
private static final int SPLASH = 0;
private static final int SELECTION = 1;
private static final int SETTINGS = 2;
private static final int FRAGMENT_COUNT = SETTINGS +1;
private Fragment[] fragments = new Fragment[FRAGMENT_COUNT];
private MenuItem settings;
private boolean isResumed = false;
private boolean userSkippedLogin = false;
private UiLifecycleHelper uiHelper;
/* Errors on the next line:
Multiple markers at this line
- Session.StatusCallback cannot be resolved to a type
- Session.StatusCallback cannot be resolved to a type
- Watchpoint:FBLoginActivity [access and modification] -
callback */
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
userSkippedLogin = savedInstanceState.getBoolean(USER_SKIPPED_LOGIN_KEY);
}
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getSupportFragmentManager();
SplashFragment splashFragment = (SplashFragment) fm.findFragmentById(R.id.splashFragment);
fragments[SPLASH] = splashFragment;
fragments[SELECTION] = fm.findFragmentById(R.id.selectionFragment);
fragments[SETTINGS] = fm.findFragmentById(R.id.userSettingsFragment);
FragmentTransaction transaction = fm.beginTransaction();
for(int i = 0; i < fragments.length; i++) {
transaction.hide(fragments[i]);
}
transaction.commit();
splashFragment.setSkipLoginCallback(new SplashFragment.SkipLoginCallback() {
#Override
public void onSkipLoginPressed() {
userSkippedLogin = true;
showFragment(SELECTION, false);
}
});
}
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
isResumed = true;
// Call the 'activateApp' method to log an app event for use in analytics and advertising reporting. Do so in
// the onResume methods of the primary Activities that an app may be launched into.
AppEventsLogger.activateApp(this);
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
isResumed = false;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
outState.putBoolean(USER_SKIPPED_LOGIN_KEY, userSkippedLogin);
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// if the session is already open, try to show the selection fragment
showFragment(SELECTION, false);
userSkippedLogin = false;
} else if (userSkippedLogin) {
showFragment(SELECTION, false);
} else {
// otherwise present the splash screen and ask the user to login, unless the user explicitly skipped.
showFragment(SPLASH, false);
}
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// only add the menu when the selection fragment is showing
if (fragments[SELECTION].isVisible()) {
if (menu.size() == 0) {
settings = menu.add(R.string.settings);
}
return true;
} else {
menu.clear();
settings = null;
}
return false;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.equals(settings)) {
showSettingsFragment();
return true;
}
return false;
}
public void showSettingsFragment() {
showFragment(SETTINGS, true);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (isResumed) {
FragmentManager manager = getSupportFragmentManager();
int backStackSize = manager.getBackStackEntryCount();
for (int i = 0; i < backStackSize; i++) {
manager.popBackStack();
}
// check for the OPENED state instead of session.isOpened() since for the
// OPENED_TOKEN_UPDATED state, the selection fragment should already be showing.
if (state.equals(SessionState.OPENED)) {
showFragment(SELECTION, false);
} else if (state.isClosed()) {
showFragment(SPLASH, false);
}
}
}
private void showFragment(int fragmentIndex, boolean addToBackStack) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
for (int i = 0; i < fragments.length; i++) {
if (i == fragmentIndex) {
transaction.show(fragments[i]);
} else {
transaction.hide(fragments[i]);
}
}
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
}
The error was resolved by removing the statement
import android.service.textservice.SpellCheckerService.Session;
and instead adding:
import com.facebook.Session;
Related
I am displaying an error message from an AsyncTask to my Fragment but when my app is on background the app is crashing.
the code is below:
import android.support.v4.app.FragmentManager;
public class AppUtil {
public static void showErrorDialog(FragmentManager fm, int messageResourceId) {
if (fm != null && !fm.isDestroyed()) {
InfoDialogFragment.newInstance("", messageResourceId).show(fm, "ERROR");
}
}
public static boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
}
}
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class BlankFragment extends Fragment implements ILoginable,
View.OnClickListener {
private ProgressDialog pd ;
public BlankFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_blank,
container, false);
rootView.findViewById(R.id.pressBT).setOnClickListener(this);
return rootView;
}
#Override
public void starProgress(int messageId) {
if (pd == null) {
pd = new ProgressDialog(getContext(), R.string.loading);
pd.show();
}
}
#Override
public void endProgress() {
if(pd != null && isAdded()) {
pd.dismiss();
pd = null;
}
}
#Override
public void displayError(int messageId) {
if (isAdded()) {
AppUtil.showErrorDialog(getFragmentManager(), R.string.app_name);
}
}
#Override
public void loginResult(boolean success) {
}
#Override
public void onClick(View v) {
if (R.id.pressBT == v.getId()) {
new LoginAsyncTask(this).execute("x");
}
}
}
public interface ILoginable {
void starProgress(int messageId);
void endProgress();
void displayError(int messageId);
void loginResult(boolean success);
}
import android.os.AsyncTask;
import java.lang.ref.WeakReference;
public class LoginAsyncTask extends AsyncTask<String, Void, String> {
private WeakReference<ILoginable> reference;
public LoginAsyncTask(ILoginable iLoginable) {
reference = new WeakReference<>(iLoginable);
}
#Override
protected void onPreExecute() {
reference.get().starProgress(R.string.loading);
}
#Override
protected String doInBackground(String... strings) {
return "xx";
}
#Override
protected void onPostExecute(String s) {
if (reference.get() != null) {
reference.get().endProgress();
reference.get().displayError(R.string.hello_blank_fragment);
}
reference.clear();
}
}
As you can see, this is a simple behavior for a basic asyncTask. However I can not figure out why the isAdded method returns true when the app is on background and also why the app is crashing with the message:
*** Process: com.roscasend.android.testadd, PID: 2891
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2053)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2079)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:678)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:632)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)
at com.roscasend.android.testadd.AppUtil.showErrorDialog(AppUtil.java:17)
at com.roscasend.android.testadd.BlankFragment.displayError(BlankFragment.java:51)
at com.roscasend.android.testadd.LoginAsyncTask.onPostExecute(LoginAsyncTask.java:37)
at com.roscasend.android.testadd.LoginAsyncTask.onPostExecute(LoginAsyncTask.java:15)***
Best Regards,
Aurelian
IllegalStateException: Can not perform this action after onSaveInstanceState
The Android FragmentManager uses the savedInstanceState bundle to track which fragments are currently shown to the user. If state is saved and you try to perform a fragment transaction, the system crashes because the transaction would never be seen by the user.
Newer versions of the support library offer an isStateSaved() method on the FragmentManager that you can use to check whether or not you're in the safe window to show the dialog.
#Override
public void displayError(int messageId) {
FragmentManager fm = getFragmentManager();
if (!fm.isStateSaved()) {
AppUtil.showErrorDialog(fm, R.string.app_name);
}
}
However, this still leaves you with a problem. If your AsyncTask finishes and tries to show an error when state has already been saved, the user will never see the error.
You can have the app record that it tried to show an error, and then also perform a check when your app resumes to see if it should show the error now. We need a place to save the information that we tried to show a dialog, and it can't just be a boolean on the activity/fragment (because that would be subject to the same state saving problem). I recommend SharedPreferences to store the info.
Add this code to your fragment:
private static final String SHOW_DIALOG = "SHOW_DIALOG";
private SharedPreferences getSharedPreferences() {
return getActivity().getPreferences(Context.MODE_PRIVATE);
}
And then use this code to show the dialog:
#Override
public void displayError(int messageId) {
FragmentManager fm = getFragmentManager();
if (!fm.isStateSaved()) {
AppUtil.showErrorDialog(getFragmentManager(), R.string.app_name);
} else {
getSharedPreferences()
.edit()
.putBoolean(SHOW_DIALOG, true)
.apply();
}
}
And this code to show the dialog when the app resumes:
#Override
public void onResume() {
super.onResume();
SharedPreferences prefs = getSharedPreferences();
boolean triedToShowInBackground = prefs.getBoolean(SHOW_DIALOG, false);
if (triedToShowInBackground) {
AppUtil.showErrorDialog(getFragmentManager(), R.string.app_name);
prefs.edit().remove(SHOW_DIALOG).apply();
}
}
the fragment is always attached even your app is in background, i think that u can use isVisible(), return true if the fragment is currently visible to the user. so if the fragment is visible show dialog
If you try to show the FragmentDialog using commitAllowingStateLoss() instead of commit(), the problem get solved. To imitate the parent show method and set internal fields, we must use reflection. You can override show method in your InfoDialogFragment class as following:
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import java.lang.reflect.Field;
public class InfoDialogFragment extends DialogFragment {
#Override
public void show(FragmentManager manager, String tag) {
try {
Field mDismissedField = DialogFragment.class.getField("mDismissed");
mDismissedField.setAccessible(true);
mDismissedField.setBoolean(this, false);
Field mShownByMeField = DialogFragment.class.getField("mShownByMe");
mShownByMeField.setAccessible(true);
mShownByMeField.setBoolean(this, true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
// Other parts of code ...
}
Try adding this in your fragment
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser && isResumed())
onResume();
}
#Override
public void onResume() {
super.onResume();
if(!getUserVisibleHint()){
return;
}
// Populate UI
}
so I'm trying to refactor my app that uses the Facebook API to use fragments instead of activities. Before, after logging in with Facebook, I would get taken to a new activity - now, I'm trying to use fragments instead. However, ever since I started using fragments, it's been failing during requests, giving me an error "Session provided to a Request in un-opened state"
I added all the UIHelper lifecycle methods to my fragment, but I'm still getting the error. I basically copied the exact code that the example fragment uses, and I'm still getting this issue. Can anybody help me out? Here's my fragment, and the activity that sets it up (most of it is stock code taken directly from Facebook's example)
Fragment:
public class ConvoFragment extends Fragment {
String name;
ListView convos;
SwipeRefreshLayout rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
rootView = (SwipeRefreshLayout)inflater.inflate(R.layout.convos_fragment,
container, false);
convos = (ListView) rootView.findViewById(R.id.conversation_list);
name = getActivity().getSharedPreferences("global", 0).getString("myName", "");
Session session = Session.getActiveSession();
RequestAsyncTask req = new Request(session, "/me/inbox/", null, HttpMethod.GET, new Request.Callback()
{
public void onCompleted(Response response)
{
final Response resp = response;
try
{
if (response != null)
{
GraphObject asdf2 = response.getGraphObject();
Log.i("graphobject", response.toString());
//This logs the Session Provided to Request in unopened state error. Everything below will fail
JSONObject obj = asdf2.getInnerJSONObject();
JSONArray threads= obj.getJSONArray("data");
final ConvoAdapter adapter = new ConvoAdapter(getActivity(), convertArray(threads), name);
convos.setAdapter(adapter);
setupRefreshListener();
setupItemListener(adapter);
}
}
catch (JSONException e)
{
e.printStackTrace();
}
}
}).executeAsync();
return rootView;
}
So it fails right as it makes the request, because the request essentially returns null. Here's my activity that sets up the fragments:
public class LoginActivity extends AppCompatActivity {
private static final String USER_SKIPPED_LOGIN_KEY = "user_skipped_login";
private static final int SPLASH = 0;
public static final int FILE = 1;
public static final int CONVOS = 2;
public static final int SETTINGS = 3;
public static final int ABOUT = 4;
private static final int FRAGMENT_COUNT = ABOUT +1;
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
private Fragment[] fragments = new Fragment[FRAGMENT_COUNT];
private boolean isResumed = false;
private boolean userSkippedLogin = false;
private UiLifecycleHelper uiHelper;
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
userSkippedLogin = savedInstanceState.getBoolean(USER_SKIPPED_LOGIN_KEY);
}
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
getSupportActionBar().setLogo(R.drawable.chatstatssmall);
FragmentManager fm = getSupportFragmentManager();
MainFragment splashFragment = (MainFragment) fm.findFragmentById(R.id.splashFragment);
fragments[SPLASH] = splashFragment;
fragments[FILE] = fm.findFragmentById(R.id.fileFragment);
fragments[CONVOS] = fm.findFragmentById(R.id.convoFragment);
fragments[SETTINGS] = fm.findFragmentById(R.id.userSettingsFragment);
fragments[ABOUT] = fm.findFragmentById(R.id.aboutFragment);
FragmentTransaction transaction = fm.beginTransaction();
for(int i = 0; i < fragments.length; i++) {
transaction.hide(fragments[i]);
}
transaction.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
android.support.v7.app.ActionBar act = getSupportActionBar();
act.setTitle("Welcome to ChatStats!");
act.setHomeAsUpIndicator(R.drawable.chatstatssmall);
act.setHomeButtonEnabled(true);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_settings:
showFragment(SETTINGS, false);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public final static String extra_msg = "chatstats.passArray";
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
isResumed = true;
// Call the 'activateApp' method to log an app event for use in analytics and advertising reporting. Do so in
// the onResume methods of the primary Activities that an app may be launched into.
AppEventsLogger.activateApp(this);
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
isResumed = false;
// Call the 'deactivateApp' method to log an app event for use in analytics and advertising
// reporting. Do so in the onPause methods of the primary Activities that an app may be launched into.
AppEventsLogger.deactivateApp(this);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
outState.putBoolean(USER_SKIPPED_LOGIN_KEY, userSkippedLogin);
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// if the session is already open, try to show the selection fragment
userSkippedLogin = false;
showFragment(FILE, false);
} else if (userSkippedLogin) {
showFragment(FILE, false);
} else {
// otherwise present the splash screen and ask the user to login, unless the user explicitly skipped.
showFragment(SPLASH, false);
}
}
public void startMainActivity(){
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (isResumed) {
FragmentManager manager = getSupportFragmentManager();
int backStackSize = manager.getBackStackEntryCount();
for (int i = 0; i < backStackSize; i++) {
manager.popBackStack();
}
// check for the OPENED state instead of session.isOpened() since for the
// OPENED_TOKEN_UPDATED state, the selection fragment should already be showing.
if (state.equals(SessionState.OPENED)) {
showFragment(FILE, false);
} else if (state.isClosed()) {
showFragment(SPLASH, false);
}
}
}
public void showFragment(int fragmentIndex, boolean addToBackStack) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
for (int i = 0; i < fragments.length; i++) {
if (i == fragmentIndex) {
transaction.show(fragments[i]);
} else {
transaction.hide(fragments[i]);
}
}
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
}
This uiHelper stuff is really confusing me. I'd appreciate if anybody could let me know what I might be doing wrong. I thought I followed the Facebook documentation (available here https://developers.facebook.com/docs/reference/android/3.23.1/class/UiLifecycleHelper/ ) exactly, but I'm still getting this error.
I am new to android and was trying the Facebook login tutorial on following URl: https://developers.facebook.com/docs/android/scrumptious/authenticate/
I have created app exactly as explained in the tutorial. However, when i try to authenticate using facebook it fails. No error is shown in logcat. Everything seems fine, not even a single error, still its not authenticating.
Here is the code, its exactly same as in tutorial.
package com.l****.n****;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
public class MainActivity extends FragmentActivity {
private static final int SPLASH = 0;
private static final int SELECTION = 1;
private static final int FRAGMENT_COUNT = SELECTION +1;
private static final String TAG = null;
private Fragment[] fragments = new Fragment[FRAGMENT_COUNT];
private boolean isResumed = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
fragments[SPLASH] = fm.findFragmentById(R.id.splashFragment);
fragments[SELECTION] = fm.findFragmentById(R.id.selectionFragment);
FragmentTransaction transaction = fm.beginTransaction();
for(int i = 0; i < fragments.length; i++) {
transaction.hide(fragments[i]);
}
transaction.commit();
}
private void showFragment(int fragmentIndex, boolean addToBackStack) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
for (int i = 0; i < fragments.length; i++) {
if (i == fragmentIndex) {
transaction.show(fragments[i]);
} else {
transaction.hide(fragments[i]);
}
}
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
#Override
public void onResume() {
super.onResume();
uiHelper.onResume();
isResumed = true;
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
isResumed = false;
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
// Only make changes if the activity is visible
if (isResumed) {
FragmentManager manager = getSupportFragmentManager();
// Get the number of entries in the back stack
int backStackSize = manager.getBackStackEntryCount();
// Clear the back stack
for (int i = 0; i < backStackSize; i++) {
manager.popBackStack();
}
if (state.isOpened()) {
// If the session state is open:
// Show the authenticated fragment
Log.i(TAG, "Logged in...");
showFragment(SELECTION, false);
} else if (state.isClosed()) {
// If the session state is closed:
// Show the login fragment
Log.i(TAG, "Logged out...");
showFragment(SPLASH, false);
}
}
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// if the session is already open,
// try to show the selection fragment
showFragment(SELECTION, false);
} else {
// otherwise present the splash screen
// and ask the person to login.
showFragment(SPLASH, false);
}
}
private UiLifecycleHelper uiHelper;
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);
}
}
Please help as i have no clue what is wrong with the code. Thanks in advance.
P.S: I am running it on real device android version 4.2.2
Check app Id and key hash are correct. If not, i would just download folder into eclipse as an existing android project.
I have a android application through which i have to login to facebook.
I am using the session object of facebook sdk to login.
However the login does not work if the device has the actual facebook application installed in it.
Below is my code
public class FacebookSettings extends FragmentActivity{
/** Called when the activity is first created. */
private static final int LOGIN = 0;
private static final int LOGGED_IN = 1;
private static final int FRAGMENT_COUNT = LOGGED_IN +1;
private Button publishButton;
private Fragment[] fragments = new Fragment[FRAGMENT_COUNT];
private Session mSession;
private boolean isResumed = false;
#Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
uiHelper.onPause();
isResumed=false;
}
#Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
uiHelper.onResume();
isResumed=true;
}
protected static final String LOG_TAG = "FACEBOOK_TEST";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fb_settings);
publishButton=(Button) findViewById(R.id.publishButton);
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
fragments[LOGIN] = fm.findFragmentById(R.id.Login_Fragment);
fragments[LOGGED_IN] = fm.findFragmentById(R.id.Logged_in_Fragment);
android.support.v4.app.FragmentTransaction transaction = fm.beginTransaction();
for(int i = 0; i < fragments.length; i++) {
transaction.hide(fragments[i]);
}
transaction.commit();
uiHelper = new UiLifecycleHelper(this, callBack);
uiHelper.onCreate(savedInstanceState);
}
private void showFragment(int fragmentIndex, boolean addToBackStack) {
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction transaction = fm.beginTransaction();
for (int i = 0; i < fragments.length; i++) {
if (i == fragmentIndex) {
transaction.show(fragments[i]);
} else {
transaction.hide(fragments[i]);
}
}
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
// Only make changes if the activity is visible
if (isResumed) {
Log.d("facebook","isResumed \n\n\n\n"+state.name());
android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
// Get the number of entries in the back stack
int backStackSize = manager.getBackStackEntryCount();
// Clear the back stack
for (int i = 0; i < backStackSize; i++) {
manager.popBackStack();
}
if (state.isOpened()) {
Log.d("facebook","State isOpened in on session state changed");
// If the session state is open:
// Show the authenticated fragment
publishButton.setVisibility(View.VISIBLE);
showFragment(LOGGED_IN, false);
} else if (state.isClosed()) {
Log.d("facebook","State isClosed in on session state changed");
// If the session state is closed:
// Show the login fragment
publishButton.setVisibility(View.INVISIBLE);
showFragment(LOGIN, false);
}
}
}
#Override
protected void onResumeFragments() {
// TODO Auto-generated method stub
super.onResumeFragments();
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// if the session is already open,
// try to show the selection fragment
Log.d("facebook","State isOpened in resume fragments\n\n\n");
publishButton.setVisibility(View.VISIBLE);
showFragment(LOGGED_IN, false);
} else {
// otherwise present the splash screen
// and ask the user to login.
Log.d("facebook","State isClosed in resume fragments\n\n\n");
publishButton.setVisibility(View.INVISIBLE);
showFragment(LOGIN, false);
}
}
private UiLifecycleHelper uiHelper;
private Session.StatusCallback callBack=new StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
// TODO Auto-generated method stub
Log.d("facebook","in status call back \n\n\n\n");
Log.d("facebook","state\n\n\n\n"+session.isClosed());
Log.d("facebook","state\n\n\n\n"+session.isOpened());
Log.d("facebook","state\n\n\n\n"+state.isClosed());
Log.d("facebook","state\n\n\n\n"+state.isOpened());
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 onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
}
pls help
thanks
I think you are looking for this :
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/applicationId" />
This metadata is used by the facebook sdk to attach session to your application.
You can also set it while creating a session using the builder
new Session.Builder(this).setApplicationId(Constants.Facebook.APP_ID)
Refer to the AndroidManifest.xml in HelloFacebookSample
I think the problem is that key hash, which you have entered on Facebook page is different from key hash, which is sent by Facebook application. One of the solutions is to add following code in onCreate() method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
PackageInfo info = getPackageManager().getPackageInfo(
"com.facebook.samples.loginhowto",
PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
}
} catch (NameNotFoundException e) {
} catch (NoSuchAlgorithmException e) {
}
...
Replace com.facebook.samples.loginhowto with your package information. Look in a log for the KeyHash and add it in your developer page.
Additional information you can find on Facebook Developer page facebook.
But remember, this is temporary solution and will most likely work only for account, from which you got key hash with Facebook application.
We have faced the same kind of issue, but it was in IPhone app. When we develop a facbook application in IPhone, login does not work , if have intalled fb application itself.
We resolver it, put Iphone app bundle identifier in which I was created facebook app in facebook developer page.
I hope that this kind of similar feild missing when you was created a fb app for android in db developer page. Please check it.
To begin with; Yes, I've searched for an answer to this everywhere, but no one have had the same problem that i have. This question might seem to be the same as another question on here, but it's most definitely not :)
Basically what i want to create is a "First-start" activity that consists of 4 fragments with different layouts. This I've managed to do myself. I also have an AsyncTask that will help one of the fragments with a call to a remote server to check if a user exists in a database. This also works. BUT, as soon as I rotate the phone and orientation changes the FragmentActivity is recreated (obviously =)). If i do this when I've fired the AsyncTask, it either crashes or in some cases finishes it's user check.
So my question is: How do I preserve the state of the AsyncTask if orientation changes?
I've seen some basic solutions using callbacks and to place the AsyncTask as an inner-class. They don't work in my case due to the layout of my pager adapter and the fact that the same Fragments class is used for all four fragments that's created.
Any help is much appreciated. Examples or solutions are even more appreciated! =)
See below for the (ugly) code that makes all of this come to life.
FirstRunActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.iqqn.***.R;
import com.viewpagerindicator.IconPageIndicator;
import com.viewpagerindicator.PageIndicator;
public class FirstRunActivity extends SherlockFragmentActivity {
private FragmentAdapter mAdapter;
private ViewPager mPager;
private PageIndicator mIndicator;
private boolean userExit = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_run);
mAdapter = new FragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (IconPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.first_run, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_exit:
userExit = true;
this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
};
#Override
public void finish() {
// Prepare data intent
Intent data = new Intent();
if(userExit) {
data.putExtra("exit", true);
setResult(RESULT_CANCELED, data);
} else {
data.putExtra("signedIn", true);
data.putExtra("registered", true);
data.putExtra("acceptedEULA", true);
// Activity finished ok, return the data
setResult(RESULT_OK, data);
}
super.finish();
}
}
FragmentAdapter.java
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.iqqn.***.R;
import com.viewpagerindicator.IconPagerAdapter;
class FragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
protected static final int[] CONTENT = new int[] { R.layout.***_welcome_1, R.layout.***_welcome_2, R.layout.***_welcome_3, R.layout.***_welcome_4};
protected static final String[] CONTENTTITLE = new String[] { "Welcome","Account","Intro","Let's start!" };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
R.drawable.perm_group_location
};
private int mCount = CONTENT.length;
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return Fragments.newInstance(CONTENT[position % CONTENT.length],position);
}
#Override
public int getCount() {
return mCount;
}
#Override
public CharSequence getPageTitle(int position) {
return FragmentAdapter.CONTENTTITLE[position % CONTENT.length];
}
#Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
Fragments.java
public final class Fragments extends SherlockFragment {
private static final String KEY_CONTENT = "Fragments:Content";
private int position = -1;
private RegisterAsyncTaskHelper registerTask = null;
public static Fragments newInstance(int content, int position) {
Fragments fragment = new Fragments();
fragment.mContent = content;
fragment.position = position;
return fragment;
}
private int mContent = -1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getInt(KEY_CONTENT);
}
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onDestroy() {
if (registerTask != null) {
registerTask.cancel(false);
}
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(mContent, container, false);
switch(position) {
case 0:
break;
case 1:
final Button btnRegister;
final Button btnLinkToLogin;
btnRegister = (Button) view.findViewById(R.id.btnRegister);
btnLinkToLogin = (Button) view.findViewById(R.id.btnLinkToLoginScreen);
// Register Button Click event
btnRegister.setOnClickListener(new View.OnClickListener() {
public void onClick(View localview) {
// Execute register task
registerTask = new RegisterAsyncTaskHelper(getActivity(), view);
if(registerTask != null)
registerTask.execute();
}
});
// Link to Login Screen
btnLinkToLogin.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
// TODO Login
}
});
break;
case 2:
break;
case 3:
break;
default:
break;
}
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_CONTENT, mContent);
}
}
RegisterAsyncTaskHelper.java
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.iqqn.***.R;
import com.iqqn.***.utils.DatabaseHandler;
import com.iqqn.***.utils.UserFunctions;
public class RegisterAsyncTaskHelper extends AsyncTask<Void, Integer, Void> {
// JSON Response node names
private static final String KEY_SUCCESS = "success";
private static final String KEY_ERROR = "error";
private static final String KEY_ERROR_MSG = "error_msg";
private static final String KEY_UID = "uid";
private static final String KEY_NAME = "name";
private static final String KEY_EMAIL = "email";
private static final String KEY_CREATED_AT = "created_at";
private View view = null;
private FragmentActivity activity = null;
private ProgressBar mProgress;
public RegisterAsyncTaskHelper(FragmentActivity activity, View view) {
this.view = view;
this.activity = activity;
this.mProgress = (ProgressBar) view.findViewById(R.id.registerProgress);
}
#Override
protected void onPreExecute() {
mProgress.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
final EditText inputFullName;
final EditText inputEmail;
final EditText inputPassword;
final TextView registerErrorMsg;
// Importing all assets like buttons, text fields
inputFullName = (EditText) view.findViewById(R.id.registerName);
inputEmail = (EditText) view.findViewById(R.id.registerEmail);
inputPassword = (EditText) view.findViewById(R.id.registerPassword);
registerErrorMsg = (TextView) view.findViewById(R.id.register_error);
String name = inputFullName.getText().toString();
String email = inputEmail.getText().toString();
String password = inputPassword.getText().toString();
UserFunctions userFunction = new UserFunctions();
JSONObject json = userFunction.registerUser(name, email, password);
// check for login response
try {
if (json.getString(KEY_SUCCESS) != null) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
registerErrorMsg.setText("");
}
});
String res = json.getString(KEY_SUCCESS);
if(Integer.parseInt(res) == 1){
// user successfully registred
// Store user details in SQLite Database
DatabaseHandler db = new DatabaseHandler(activity.getApplicationContext());
JSONObject json_user = json.getJSONObject("user");
// Clear all previous data in database
userFunction.logoutUser(activity.getApplicationContext());
db.addUser(json_user.getString(KEY_NAME), json_user.getString(KEY_EMAIL), json.getString(KEY_UID), json_user.getString(KEY_CREATED_AT));
/*
// Launch Dashboard Screen
Intent dashboard = new Intent(ctx, DashboardActivity.class);
// Close all views before launching Dashboard
dashboard.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(dashboard);
// Close Registration Screen
finish();
*/
}else{
// Error in registration
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
registerErrorMsg.setText("Error occured in registration");
}
});
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(final Integer... values) {
}
#Override
protected void onPostExecute(final Void result) {
mProgress.setVisibility(View.GONE);
}
}
Just to clarify. This code is in no way supposed to look good as of now. But it will after i get this working.
// Alexander
How do I preserve the state of the AsyncTask if orientation changes?
Have the AsyncTask be managed by a retained fragment (i.e., a dynamic fragment that calls setRetainInstance(true) on itself). That fragment will survive the configuration change.
They don't work in my case due to the layout of my pager adapter and the fact that the same Fragments class is used for all four fragments that's created.
Then add a fifth fragment for the AsyncTask. It does not have to participate in the UI:
if (getSupportFragmentManager().findFragmentByTag(MODEL)==null) {
model=new ModelFragment();
getSupportFragmentManager().beginTransaction().add(model, MODEL)
.commit();
}
Here, ModelFragment is the Fragment responsible for the AsyncTask (and any portion of the data model needed by the activity not held in memory anywhere else). We only create the fragment if it does not already exist under its tag (MODEL).
Use AsyncTaskLoader to save state and result of the task.
What I've done in situations like this is use a BroadcastReceiver. Instead of tightly coupling your AsyncTask with your FragmentActivity, I would suggesting using a Thread to run your background operation and calling context.sendBroadcast(...), then receiving that broadcast in your FragmentActivity.
Use an intent service plus a LocalBroadcastManager in the target fragment