Overview
This tutorial assumes you have done some preliminary setup:
- Installed the Android SDK & the Eclipse Plugin
- Downloaded the facebook-android-sdk
- Created a Facebook App
If you have not done this yet, follow the Facebook Android Developer Guide Once you have done the preliminary setup, you need to export your app’s signature with the following keytool command:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
this keytool command generates a string the must registered in the Mobile and Devices section of your app.
Part 1: Creating a new facebook-android-sdk Eclipse Project
Create a new Android Project in eclipse:
Now that we have created a new Android Project, we need to reference the facebook project we setup during the Facebook Android Developer Guide by going right-clicking your Android Project and going to Properties->Android->Add..

Part 2: Project Setup
1. Update the Manifest
First we need to update the AndroidManifest.xml file to allow for internet access, otherwise this will not work. Add the following code between the application tags:
<uses-permission android:name="android.permission.INTERNET" />
2. Instance Variables
Next we need to add some instance variables to our activity:
package com.eosgood.tutorials; import com.facebook.android.AsyncFacebookRunner; import com.facebook.android.Facebook; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class FacebookTutorialActivity extends Activity { // application id from facebook.com/developers public static final String APP_ID = "your_id_here"; // log tag for any log.x statements public static final String TAG = "FACEBOOK CONNECT"; // permissions array private static final String[] PERMS = new String[] { "user_events" }; // facebook vars private Facebook mFacebook; private AsyncFacebookRunner mAsyncRunner; // id text view private TextView mText; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
- APP_ID can be retrieved from Your App Page
- TAG is for debug statement tagging
- PERMS is a string array of the permissions you are requesting
- mText is will display messages to the user
Part 3: Setting up the Layout
Before we can start using the facebook sdk, we need to create a simple layout. I chose to do it dynamically but you could do it in xml, your choice. Here is the java code for the initLayout() function:
protected void initLayout() { LinearLayout rootView = new LinearLayout(this.getApplicationContext()); rootView.setOrientation(LinearLayout.VERTICAL); this.mText = new TextView(this.getApplicationContext()); this.mText.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); rootView.addView(this.mText); this.setContentView(rootView); }
This code adds creates a LinearLayout and adds our mText TextView to it and then sets it as our Activity’s ContentView.
Part 4: Filling in onCreate()
Now that we have setup our instance variables and a have simple layout its time use them:
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (APP_ID == null || APP_ID.equals("")) { Util.showAlert(this, "Warning", "Facebook Applicaton ID must be " + "specified before running"); } // setup the content view initLayout(); mText.setText("Login Please"); // setup the facebook session mFacebook = new Facebook(APP_ID); mAsyncRunner = new AsyncFacebookRunner(mFacebook); }
This code will setup the layout, set the text for our mText TextView and initialize the facebook variables (what we really care about). YOU MUST SET YOUR APP_ID OTHERWISE NOTHING WILL WORK.
Part 5: Creating the Options Menu
Since this is just a simple tutorial I chose to use the options menu for login/logout and retrieving the userID and later, events. Setting up the options menu comes in three parts: onPrepareOptionsMenu, onCreateOptionsMenu and onOptionsItemSelected. For this to work, we are going to have to add some more instance variables:
public static final int LOGIN = Menu.FIRST; public static final int GET_EVENTS = Menu.FIRST + 1; public static final int GET_ID = Menu.FIRST + 2;
5.1 onCreateOptionsMenu
Since this only gets called once, its pretty simple to create an options menu (the menu that shows when you press the menu button):
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(Menu.NONE, LOGIN, Menu.NONE, "Login Text"); menu.add(Menu.NONE, GET_EVENTS, Menu.NONE, "Get Events"); menu.add(Menu.NONE, GET_ID, Menu.NONE, "Get UserID"); return true; }
5.2 onPrepareOptionsMenu
This function will be called every time the menu button is pressed and is a bit more complicated:
@Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem loginItem = menu.findItem(Menu.FIRST); MenuItem getID = menu.findItem(GET_ID); if (mFacebook.isSessionValid()) { loginItem.setTitle("Logout"); getID.setEnabled(true); } else { loginItem.setTitle("Login"); getID.setEnabled(false); } loginItem.setEnabled(true); return super.onPrepareOptionsMenu(menu); }
5.3 onOptionsItemSelected
Whenever an item is pressed in the options menu, this function will be called. This is where we begin to call the facebook variables!
@Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId) { case LOGIN: if (mFacebook.isSessionValid()) { mText.setText("Logging out..."); AsyncFacebookRunner asyncRunner = new AsyncFacebookRunner( mFacebook); asyncRunner.logout(this, new LogoutRequestListener()); } else { mFacebook.authorize(this, PERMS, new LoginDialogListener()); } break; case GET_ID: mAsyncRunner.request("me", new IDRequestListener()); break; case GET_EVENTS: mAsyncRunner.request("me/events", new EventRequestListener()); break; default: return false; } return true; }
So, if the Login/Logout button is pressed in the login state, mFacebook attempts to authorize using the permissions we specified and then posting its results to LoginDialogListener which is a private class of our Activity.
Part 6: Implementing the DialogListener Interface
You could implement this interface by creating an inline class but I think the code is much more readable if you create a private inner class eg
private class LoginDialogListener implements DialogListener
This is a very simple class that simply changes the text of our mText instance variable also, after onComplete is called, mFAcebook.isSessionValid() will now return true. Here is the code for LoginDialogListener:
private class LoginDialogListener implements DialogListener { public void onComplete(Bundle values) { mText.setText("Facebook login successful. Press Menu..."); } public void onFacebookError(FacebookError e) { // TODO Auto-generated method stub } public void onError(DialogError e) { // TODO Auto-generated method stub } public void onCancel() { // TODO Auto-generated method stub } }
I should probably have some Log.d(TAG, e.getLocalizedMessage()) statements but I’m a lazy programmer…
Part 7: Implementing the RequestListener Interface
7.1 Logging Out
Again you could just do this inline. This private class:
private class LogoutRequestListener implements RequestListener
takes care of the logout process. For this to work, we are going to have to add a Handler instance variable to our class:
private Handler mHandler = new Handler();
private class LogoutRequestListener implements RequestListener { public void onComplete(String response, Object state) { // Dispatch on its own thread mHandler.post(new Runnable() { public void run() { mText.setText("Logged out"); } }); } public void onIOException(IOException e, Object state) { // TODO Auto-generated method stub } public void onFileNotFoundException(FileNotFoundException e, Object state) { // TODO Auto-generated method stub } public void onMalformedURLException(MalformedURLException e, Object state) { // TODO Auto-generated method stub } public void onFacebookError(FacebookError e, Object state) { // TODO Auto-generated method stub } }
Since the logout process may take some time, a new thread is dispatched to run and then update the ui when it completes. If this is not done, the app can freeze up since the Android OS stops any apps that take more than 5sec to respond.
7.2 Downloading the UserID
Finally, how to download the UserID.
case GET_ID: mAsyncRunner.request("me", new IDRequestListener()); break;
is the code that uses our final private class:
private class IDRequestListener implements RequestListener
again the onComplete() method is key here:
private class IDRequestListener implements RequestListener { public void onComplete(String response, Object state) { try { // process the response here: executed in background thread Log.d(TAG, "Response: " + response.toString()); JSONObject json = Util.parseJson(response); final String id = json.getString("id"); // then post the processed result back to the UI thread // if we do not do this, an runtime exception will be generated // e.g. "CalledFromWrongThreadException: Only the original // thread that created a view hierarchy can touch its views." FacebookTutorialActivity.this.runOnUiThread(new Runnable() { public void run() { userID = id; mText.setText("Hello there, " + id + "!"); } }); } catch (JSONException e) { Log.w(TAG, "JSON Error in response"); } catch (FacebookError e) { Log.w(TAG, "Facebook Error: " + e.getMessage()); } } public void onIOException(IOException e, Object state) { // TODO Auto-generated method stub } public void onFileNotFoundException(FileNotFoundException e, Object state) { // TODO Auto-generated method stub } public void onMalformedURLException(MalformedURLException e, Object state) { // TODO Auto-generated method stub } public void onFacebookError(FacebookError e, Object state) { // TODO Auto-generated method stub } }
7.3 Downloading the User’s Events
First, we need to create a class for viewing these events:
package com.eosgood.tutorials; public class FbEvent { private String id; private String title; private String startTime; private String endTime; private String location; public FbEvent(String _id, String _title, String _sT, String _eT, String _loc){ this.id = _id; this.title = _title; this.startTime = _sT; this.endTime = _eT; this.location = _loc; } public String getId(){ return id; } public String getTitle(){ return title; } public String getStartTime(){ return startTime; } public String getEndTime(){ return endTime; } public String getLocation(){ return location; } }
Now we can display info about the user’s events we need to request all the user’s event from the api using our last private class:
private class EventRequestListener implements RequestListener
private class EventRequestListener implements RequestListener { public void onComplete(String response, Object state) { try { // process the response here: executed in background thread Log.d(TAG, "Response: " + response.toString()); final JSONObject json = new JSONObject(response); JSONArray d = json.getJSONArray("data"); for (int i = 0; i < d.length(); i++) { JSONObject event = d.getJSONObject(i); FbEvent newEvent = new FbEvent(event.getString("id"), event.getString("name"), event.getString("start_time"), event.getString("end_time"), event.getString("location")); events.add(newEvent); } // then post the processed result back to the UI thread // if we do not do this, an runtime exception will be generated // e.g. "CalledFromWrongThreadException: Only the original // thread that created a view hierarchy can touch its views." FacebookTutorialActivity.this.runOnUiThread(new Runnable() { public void run() { for (FbEvent event : events) { TextView view = new TextView( getApplicationContext()); view.setText(event.getTitle()); view.setTextSize(16); eventLayout.addView(view); } } }); } catch (JSONException e) { Log.w(TAG, "JSON Error in response"); } } public void onIOException(IOException e, Object state) { // TODO Auto-generated method stub } public void onFileNotFoundException(FileNotFoundException e, Object state) { // TODO Auto-generated method stub } public void onMalformedURLException(MalformedURLException e, Object state) { // TODO Auto-generated method stub } public void onFacebookError(FacebookError e, Object state) { // TODO Auto-generated method stub } }
This class requests all the events for the user and then adds to the rootView in a asynchronous fashion.
The END
Feel free to clone / fork this code on github
