I get this exception, "Can't create handler inside thread that has not called Looper.prepare()", thrown when I call either get or getFriends. Here is the code I use for getFriends. It is called from the main thread.
public void returnFriendIDs(final int pointer){
Properties properties = new Properties.Builder()
.add(Profile.Properties.ID)
.add(Profile.Properties.FIRST_NAME)
.add(Profile.Properties.LAST_NAME)
.add(Profile.Properties.INSTALLED)
.build();
try{
mSimpleFacebook.getFriends(properties, new OnFriendsListener() {
@Override
public void onComplete(List<Profile> friends) {
String resultStr = "";
Log.d(LOGPREFIX, "Number of friends = " + friends.size());
for(Profile p : friends){
resultStr += p.getId()+',';
}
if(friends.size() > 0) returnFriends(pointer, resultStr.substring(0,resultStr.length()-1));
else returnFriends(pointer, "");
}
@Override
public void onFail(String reason){
returnFriends(pointer, "");
}
@Override
public void onException(Throwable throwable){
Log.w(LOGPREFIX, throwable.getMessage());
returnFriends(pointer, "");
}
});
}
catch(Throwable throwable){
Log.w(LOGPREFIX, "In getFriends"+throwable.getMessage());
}
}
I've tried calling Looper.prepare() before calling getFriends, but that just leads to none of the callbacks ever getting called.
My onActivityResult function is
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
//Log.w(LOGPREFIX, "onActivityResult() called.");
mSimpleFacebook.onActivityResult(this, requestCode, resultCode, data);
// Handle InApp Purchase call results
if(REQUEST_INAPP_PURCHASE == requestCode)
{
if (!mBillingHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
The stacktrace is:
Pending exception java.lang.RuntimeException thrown by 'unknown throw location'
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at void android.os.Handler.<init>(android.os.Handler$Callback, boolean) (Handler.java:200)
at void android.os.Handler.<init>() (Handler.java:114)
at void com.facebook.RequestAsyncTask.onPreExecute() (RequestAsyncTask.java:146)
at android.os.AsyncTask android.os.AsyncTask.executeOnExecutor(java.util.concurrent.Executor, java.lang.Object[]) (AsyncTask.java:587)
at android.os.AsyncTask android.os.AsyncTask.execute(java.lang.Object[]) (AsyncTask.java:535)
at void com.sromku.simple.fb.actions.GetAction.runRequest(com.facebook.Request) (GetAction.java:143)
at void com.sromku.simple.fb.actions.GetAction.executeImpl() (GetAction.java:81)
at void com.sromku.simple.fb.actions.AbstractAction.execute() (AbstractAction.java:17)
at void com.sromku.simple.fb.SimpleFacebook.getFriends(com.sromku.simple.fb.entities.Profile$Properties, com.sromku.simple.fb.listeners.OnFriendsListener) (SimpleFacebook.java:594)
at void com.fillmyblank.app.FillMyBlank.returnFriendIDs(int) (FillMyBlank.java:325)
at void org.libsdl.app.SDLActivity.nativeInit() (SDLActivity.java:-2)
at void org.libsdl.app.SDLMain.run() (SDLActivity.java:509)
at void java.lang.Thread.run() (Thread.java:818)
It is called with this code from my main function(which I believe is the UI thread). I use the ndk so by main function I mean the actual function main.
aEnv = (JNIEnv *)SDL_AndroidGetJNIEnv();
aActivityClass = aEnv->FindClass(mClassPath.c_str());
aStaticMid = aEnv->GetStaticMethodID(aActivityClass, "GetActivity", "()Lcom/fillmyblank/app/FillMyBlank;");
aActivity = aEnv->CallStaticObjectMethod(aActivityClass, aStaticMid);
friends* fp = new friends;
fp->waiting = SDL_CreateCond();
aJavaMethodID = aEnv->GetMethodID(aActivityClass, "returnFriendIDs", "(I)V");
aEnv->CallVoidMethod(aActivity, aJavaMethodID, fp);
EDIT: Added stacktrace
EDIT: Added the calling function.
The explanation
The Exception is thrown in the
onPreExecute
part of anAsyncTask
which is part of the Facebook library (com.facebook.RequestAsyncTask
).onPreExecute
is executed in the same thread as the caller of the AsyncTask. If the caller is the ui thread, no issue, it will work. It the caller is not the ui thread, it could fail (there is a great chance). If any component of the ui or related to the ui is used, it will fail.In your case, it is not executed in the ui thread but in in a regular thread which does not have a message loop so this famous Exception is thrown :
Can't create handler inside thread that has not called Looper.prepare()
The solution
You have to use runOnUiThread method that will ensure that your code is executed in the ui thread.
runOnUiThread
takes aRunnable
as a parameter.