Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse next page of Facebook (SDK 4.0) Graph response in android?

I am fetching the list of friends who use the my android application and show them in listview. The response we get from the call:

 GraphRequestAsyncTask graphRequest = new GraphRequest(
                AccessToken.getCurrentAccessToken(),
                "/me/friends",
                null,
                HttpMethod.GET,
                new GraphRequest.Callback() {
                    public void onCompleted(GraphResponse response) {



                    }
                }
        ).executeAsync();

is

 {
  "data": [
    {
      "name": "Sanjeev Sharma",
      "id": "10XXXXXXXXXX40"
    },
    {
      "name": "Avninder Singh",
      "id": "1XXXXX30"
    },
    {
      "name": "Saikrishna Tipparapu",
      "id": "17XXXXXX98"
    },
    {
      "name": "Perfekt Archer",
      "id": "100XXXXX29"
    },
    {
      "name": "Shathyan Raja",
      "id": "10XXXXX0"
    },
    {
      "name": "Kenny Tran",
      "id": "10XXXXX36164"
    },
    {
      "name": "Lahaul Seth",
      "id": "100XXXXX161"
    },
    {
      "name": "Bappa Dittya",
      "id": "10XXXXX24"
    },
    {
      "name": "Rahul",
      "id": "10XXXXX
    },
    {
      "name": "Suruchi ",
      "id": "7XXXXXXXX11"
    }
  ],
  "paging": {
    "next": "https://graph.facebook.com/76XXXXXXXX28/friends?limit=25&offset=25&__after_id=enc_AdAXXXXX5L8nqEymMrXXXXoYWaK8BXXHrvpXp03gc1eAaVaj7Q"
  },
  "summary": {
    "total_count": 382
  }
}

Now how can we parse the next page of the result in android as it is a link for next page? The next page api call will be done through graph api or facebook only?

like image 986
Abhishek Balani Avatar asked Dec 14 '22 13:12

Abhishek Balani


2 Answers

ifaour has the right idea of how to use pagination with the next, though i think he is right i just wanted to add a recursive way to fetch all results page after page into one nice list object, this is from a project requesting user photos but its the same idea and syntax as the likes (note that this whole thing is using the execute and wait so you'll have to run this from a separate thread or you will effectively block your UI thread and eventually make the app shut itself down.

Bundle param = new Bundle();
param.putString("fields", "id,picture");
param.putInt("limit", 100);

//setup a general callback for each graph request sent, this callback will launch the next request if exists.
final GraphRequest.Callback graphCallback = new GraphRequest.Callback(){
    @Override
    public void onCompleted(GraphResponse response) {                       
        try {
            JSONArray rawPhotosData = response.getJSONObject().getJSONArray("data");
            for(int j=0; j<rawPhotosData.length();j++){
                /*save whatever data you want from the result
                JSONObject photo = new JSONObject();
                photo.put("id", ((JSONObject)rawPhotosData.get(j)).get("id"));
                photo.put("icon", ((JSONObject)rawPhotosData.get(j)).get("picture"));

                boolean isUnique = true;

                for(JSONObject item : photos){  
                    if(item.toString().equals(photo.toString())){
                        isUnique = false;
                        break;
                    }
                }

                if(isUnique) photos.add(photo);*/
            }

            //get next batch of results of exists
            GraphRequest nextRequest = response.getRequestForPagedResults(GraphResponse.PagingDirection.NEXT);
            if(nextRequest != null){
                nextRequest.setCallback(this);
                nextRequest.executeAndWait();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
};

Now all you need to do is simply make the initial request and set the callback you've made in previous step, the callback will handle all the dirty work of calling the rest of the items, this will eventually give you all the items from your request.

//send first request, the rest should be called by the callback
new GraphRequest(AccessToken.getCurrentAccessToken(), 
        "me/photos",param, HttpMethod.GET, graphCallback).executeAndWait();
like image 135
Liran Cohen Avatar answered Dec 21 '22 09:12

Liran Cohen


As mentioned by @CBroe, you use the getRequestForPagedResults method. As for an example, check the Scrumptious sample project.

I extended the HelloFacebookSample and added two buttons that will load the initial user liked pages and the other will load the next result if available:

loadAndLogLikesButton = (Button) findViewById(R.id.loadAndLogLikesButton);
loadAndLogLikesButton.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
    pendingAction = PendingAction.LOAD_LIKES;
    if (!hasUserLikesPermission()) {
      LoginManager.getInstance().logInWithReadPermissions(HelloFacebookSampleActivity.this, Arrays.asList("public_profile", "user_likes"));
    } else {
      handlePendingAction();
    }
  }
});

Now the handlePendingAction() is being called from the LoginManager success callback. As you can see, I have an extra action LOAD_LIKES that will trigger a method that will do the following:

GraphRequest request = GraphRequest.newGraphPathRequest(
  accessToken,
  "me/likes",
  new GraphRequest.Callback() {
      @Override
      public void onCompleted(GraphResponse response) {
          Log.d("HelloFacebook", response.getRawResponse());
          JSONArray data = response.getJSONObject().optJSONArray("data");

          boolean haveData = data.length() > 0;
          if (haveData) {
              loadNextLikesButton.setEnabled(true);
              nextRequest = response.getRequestForPagedResults(GraphResponse.PagingDirection.NEXT);
          }
      }
  }
);

Bundle parameters = new Bundle();
parameters.putString("fields", "id");
parameters.putString("limit", "100");
request.setParameters(parameters);

Now my loadNextLikesButton's callback looks like this:

if (nextRequest != null) {
  nextRequest.setCallback(new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      Log.d("HelloFacebook", response.getRawResponse());

      JSONArray data = response.getJSONObject().optJSONArray("data");

      boolean haveData = data.length() > 0;
      if (haveData) {
        loadNextLikesButton.setEnabled(true);
        nextRequest = response.getRequestForPagedResults(GraphResponse.PagingDirection.NEXT);
      } else {
        loadNextLikesButton.setEnabled(false);
      }
    }
  });
  nextRequest.executeAsync();
} else {
  Log.d("HelloFacebook", "We are done!");
  return;
}

Not pretty but you get the idea.

like image 35
ifaour Avatar answered Dec 21 '22 10:12

ifaour