I need to get friends details of the friends selected by the user.
The user can selected his friends using default facebook friend picker. But when I get the selection as a list of GraphUser I cannot see any details of the users. In particular, I cannot get the usernames.
Here is the Activity of the friend picker:
public class FacebookFriendPickerActivity extends FragmentActivity {
public static final String IEXTRA_SELECTED_FRIENDS = "selected friends";
private FriendPickerFragment friendPickerFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_facebook_frind_picker);
Bundle args = getIntent().getExtras();
FragmentManager manager = getSupportFragmentManager();
Fragment fragmentToShow = null;
if (savedInstanceState == null) {
friendPickerFragment = new FriendPickerFragment(args);
} else {
friendPickerFragment = (FriendPickerFragment) manager.findFragmentById(R.id.picker_fragment);
}
// Set the listener to handle errors
friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
#Override
public void onError(PickerFragment<?> fragment, FacebookException error) {
Toast.makeText(FacebookFriendPickerActivity.this, error.getLocalizedMessage(), Toast.LENGTH_LONG).show();
setResult(RESULT_CANCELED);
finish();
}
});
// Set the listener to handle button clicks
friendPickerFragment.setOnDoneButtonClickedListener(new PickerFragment.OnDoneButtonClickedListener() {
#Override
public void onDoneButtonClicked(PickerFragment<?> fragment) {
List<GraphUser> users = friendPickerFragment.getSelection();
if (users.size() > 0) {
ArrayList<String> usernames = new ArrayList<String>(users.size());
for (GraphUser user : users)
usernames.add(user.getUsername());
Intent data = new Intent();
data.putStringArrayListExtra(IEXTRA_SELECTED_FRIENDS, usernames);
setResult(RESULT_OK, data);
finish();
} else {
setResult(RESULT_CANCELED);
finish();
}
}
});
fragmentToShow = friendPickerFragment;
manager.beginTransaction().replace(R.id.picker_fragment, fragmentToShow).commit();
}
#Override
protected void onStart() {
super.onStart();
friendPickerFragment.loadData(false);
}
}
When I try to read the list of usernames, I always get null.
Thanks in advance.
When you query for friend list with basic_info permission (which is default permission), you only get id and name fields. In order to get username field, you have to add it as an extra field to your friendPickerFragment.
It can simply be done by adding this line of code
friendPickerFragment.setExtraFields(Arrays.asList("username"));
Check setExtraFields method on related document here
Related
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.
I have series of images, when pressed by user should start a new activity and pass some data (ArrayList of custom object). ArrayList of custom object is initialized based on user input. Now, I am facing problem that when user has not still given input for ArrayList and clicks any of Image, it shows application get stops. I tried to handle it through try and catch block but it does not work. The whole flow works fine when ArrayList is not empty.Image to have look at App (on Top, series of images are there which gets populated basis user selection from a list and then user can click any image of them)
Find relevant codes below:
Relevant Block from MainActivity:
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.imageView.setImageResource(horizontalList.get(position).imageId);
holder.txtview.setText(horizontalList.get(position).txt);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String list = horizontalList.get(position).txt.toString();
List<Coupon> couponList = new ArrayList<>();
try {
for (Place place : allOffers) {
Coupon coupon = new Coupon(place.mPlace, place.mOffer, place.mImage, list);
couponList.add(coupon);
}
Toast.makeText(MainActivity.this, list, Toast.LENGTH_SHORT).show();
Intent intentCat = new Intent(MainActivity.this, CategoryOffersActivity.class);
intentCat.putExtra("Category", (Serializable) couponList);
startActivity(intentCat);
} catch(Exception e) {
Toast.makeText(MainActivity.this,"List is Empty",Toast.LENGTH_SHORT).show();
}
}
});
}
New Activity which gets started when image is clicked by user:
public class CategoryOffersActivity extends AppCompatActivity implements PlaceAdapter.AdapterInterface,Serializable {
ListView catListView;
List<Place> catOffers = new ArrayList<Place>();
PlaceAdapter catPlaceAdapter;
Place [] catPlaces;
List <Coupon> listCoupon=new ArrayList<Coupon>();
TextView mHeader;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_categoryoffers);
catListView = (ListView) findViewById(R.id.catListView);
mHeader=(TextView)findViewById(R.id.categoryName);
if (getIntent() != null) {
listCoupon = (ArrayList<Coupon>) getIntent().getSerializableExtra("Category");
if (listCoupon != null) {
ArrayList<Place> placeList = new ArrayList<>();
for(Coupon coupon : listCoupon) {
Place place=new Place(coupon.mPlace,coupon.mOffer,coupon.mImage);
placeList.add(place);
}
catPlaces=placeList.toArray(new Place[placeList.size()]);
mHeader.setText(listCoupon.get(0).mItemClicked+" Coupon History");
catPlaceAdapter = new PlaceAdapter(CategoryOffersActivity.this, R.layout.row, catPlaces, this);
if (catListView != null) {
catListView.setAdapter(catPlaceAdapter);
}
}
}
}
#Override
public void buttonPressed() {
// some action
}
}
if ((listCoupon != null)&&(listCoupon.size()>0))
Also check for array size
Well I've run into an issue in my inventory app. I'm trying to retrieve a list of inventory items from Parse. This isn't the hardest thing in the world to do. At this point, I'm at a loss as to why the data is coming back as empty, when I can clearly see in Parse.com that there is data in the class I have requested from. Any ideas? (NOTE: I am able to add items to the database without a problem... it's just in the retrieval).
MainActivity:
public class MainActivity extends AppCompatActivity {
private ImageView mAddButton;
private ImageView mBackButton;
private Inventory mInventory;
private RecyclerView mRecyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAddButton = (ImageView) findViewById(R.id.addItemButton);
mBackButton = (ImageView) findViewById(R.id.backButton);
mBackButton.setVisibility(View.INVISIBLE);
mInventory = new Inventory();
ParseUser user = ParseUser.getCurrentUser();
if (user == null) {
navToLogin();
} else {
Toast.makeText(MainActivity.this, "Welcome!", Toast.LENGTH_SHORT).show();
getInventoryFromParse();
Toast.makeText(MainActivity.this, mInventory.toString(), Toast.LENGTH_LONG).show();
}
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addItem();
}
});
}
private void updateView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
InventoryListAdapter adapter = new InventoryListAdapter(this, mInventory.getItemList());
mRecyclerView.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
}
private void addItem() {
Intent intent = new Intent(MainActivity.this, AddItemActivity.class);
startActivityForResult(intent, 1);
}
private void navToLogin() {
Intent intent = new Intent(this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case (1):
updateView();
}
}
}
public void getInventoryFromParse() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Item");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
mInventory.setItemList(objects);
} else {
Toast.makeText(MainActivity.this, "There was an error.", Toast.LENGTH_LONG).show();
}
}
});
}
}
The Inventory Class:
public class Inventory {
private List<ParseObject> mItemList;
public Inventory() {
mItemList = new ArrayList<>();
}
public List<ParseObject> getItemList() {
return mItemList;
}
public void setItemList(List<ParseObject> itemList) {
mItemList = itemList;
}
public void addItem(ParseObject item) {
mItemList.add(item);
}
#Override
public String toString() {
return "Inventory{" +
"mItemList=" + mItemList +
'}';
}
}
The query creates a new thread which runs in the background, then your main thread moves on, exits the function, and the query still hasn't completed when you go to print out the inventory. setInventory has not been called when the main thread prints mInventory to string.
That's why your code isn't working.
As for a solution, I'm not sure how the Android dev kit works, but my suggestion to keep your code split up the way it is would be to make getInventoryFromParse have a return type, and call return inside of the query callback. I'm not sure if that'll throw errors since the main thread reaches the end of the function... If that doesn't work, you'll have to rewrite your code so that anything that needs to happen after the items are fetched happens inside of the callback.
EDIT-----: So I did manage to make it show me users and be able to select some, and to send me back the selected users to my app but there is a slight problem. "Uri.parse("picker://friend");" doesn't give me the list of my friends, but only a list of the friends that I have and have my app installed.
I followed this example: https://developers.facebook.com/docs/android/scrumptious/show-friends but I am trying to modify it, so basically I took out the selectionActivity and Fragment. So I have from my activity a button that calls the PickerActivity which contains FriendPickerFragment. I can select my friends from there, but back in my activities onActivityResult i get back "data" as null.
I have an Application class in my app, where i save the FB session, and also have the login function in there.
In my MainActivity onCreate I have this:
MyApp.getInstance().facebookLogin(PSAddFriendsActivity.this, new CrudStateCallback() {
#Override
public void onResponse(final String string) {
Log.i("", "session : session is opened? : " + MyApp.getInstance().fbSession.getAccessToken());
}
});
After having logged in, I instantiate a list with the current friends I have in my app, and the first position of this list is a FB button:
#Override
protected void onListItemClick(ListView l, View v, int position, long id){
super.onListItemClick(l, v, position, id);
if(position == 0){
startPickerActivity(PSPickerActivity.FRIEND_PICKER, 0);
}else if(position ==1){
//TODO: OPEN CONTACTS PAGE TO ADD FRIENDS
}
}
This is my onACtivityResult and the "startPickerActivity" from this class:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
Log.i("","--------------data is : " + data);
Log.i("","--------------resultCode is : " + resultCode);
Log.i("","--------------requestCode is : " + requestCode);
}
public void startPickerActivity(Uri data, int requestCode) {
Intent intent = new Intent();
intent.setData(data);
intent.setClass(PSAddFriendsActivity.this, PickerActivity.class);
startActivityForResult(intent, requestCode);
}
This is the PickerActivity, how I took it from FB:
public class PickerActivity extends FragmentActivity{
private FriendPickerFragment friendPickerFragment;
public static final Uri FRIEND_PICKER = Uri.parse("picker://friend");
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pickers);
Bundle args = getIntent().getExtras();
FragmentManager manager = getSupportFragmentManager();
Fragment fragmentToShow = null;
Uri intentUri = getIntent().getData();
if (FRIEND_PICKER.equals(intentUri)) {
if (savedInstanceState == null) {
friendPickerFragment = new FriendPickerFragment(args);
} else {
friendPickerFragment =
(FriendPickerFragment) manager.findFragmentById(R.id.picker_fragment);
}
// Set the listener to handle errors
friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
#Override
public void onError(PickerFragment<?> fragment,
FacebookException error) {
PSPickerActivity.this.onError(error);
}
});
// Set the listener to handle button clicks
friendPickerFragment.setOnDoneButtonClickedListener(
new PickerFragment.OnDoneButtonClickedListener() {
#Override
public void onDoneButtonClicked(PickerFragment<?> fragment) {
finishActivity();
}
});
fragmentToShow = friendPickerFragment;
} else {
// Nothing to do, finish
setResult(RESULT_CANCELED);
finish();
return;
}
manager.beginTransaction()
.replace(R.id.picker_fragment, fragmentToShow)
.commit();
}
private void onError(Exception error) {
onError(error.getLocalizedMessage(), false);
}
private void onError(String error, final boolean finishActivity) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.error_dialog_title).
setMessage(error).
setPositiveButton(R.string.error_dialog_button_text,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (finishActivity) {
finishActivity();
}
}
});
builder.show();
}
private void finishActivity() {
setResult(RESULT_OK, null);
finish();
}
#Override
protected void onStart() {
super.onStart();
if (FRIEND_PICKER.equals(getIntent().getData())) {
try {
friendPickerFragment.loadData(false);
} catch (Exception ex) {
onError(ex);
}
}
}
#Override
protected void onResume() {
Log.i("", "location test onResume");
super.onResume();
MyApp.getInstance().pref.setIsBackground(this, false);
MyApp.getInstance().startLocationClient();
}
#Override
protected void onPause() {
Log.i("", "location test onPause");
super.onPause();
MyApp.getInstance().pref.setIsBackground(this, true);
}
}
Now I looked over this fragment, do not know if I have to add something or save something from the fragment on "onDoneButtonClicked"? or what exactly, because my main activity does return null as data..
forgot to call this in the finishActivty:
if (FRIEND_PICKER.equals(getIntent().getData())) {
if (friendPickerFragment != null) {
MyApp.getInstance().setSelectedUsers(friendPickerFragment.getSelection());
}
}
Now I can get from my Application the list of selected users.
About my edit, after this i found out that with Graph2.0 you cannot get a list of your whole friendlist. You can only get back the info of friends that also liked the app. It is possible to invite friends to like an app but only if you set it as a Game from the FB developers page
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.