问题
I have a simple activity with a facebook button to use login (using Facebook Android SDK:
package com.example.adminn.facebooktest;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import android.content.Intent;
import android.view.View;
import android.app.Activity;
import android.support.v4.app.FragmentActivity;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.CallbackManager;
import com.facebook.login.LoginManager;
import com.facebook.login.widget.LoginButton;
import com.facebook.login.LoginResult;
import com.facebook.FacebookCallback;
import java.util.Arrays;
public class MainActivity extends FragmentActivity {
CallbackManager callbackManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FacebookSdk.sdkInitialize(this.getApplicationContext());
setContentView(R.layout.activity_main);
callbackManager = CallbackManager.Factory.create();
//LoginButton loginButton = (LoginButton) findViewById(R.id.login_button);
LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
//Toast toast = Toast.makeText(MainActivity.this, "OnSuccess:" + loginResult.getAccessToken().toString(), Toast.LENGTH_LONG);
//toast.show();
}
@Override
public void onCancel() {
Toast toast = Toast.makeText(MainActivity.this, "Cancel!!", Toast.LENGTH_LONG);
toast.show();
}
@Override
public void onError(FacebookException e) {
Toast toast = Toast.makeText(MainActivity.this, "Error!", Toast.LENGTH_LONG);
toast.show();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode,final Intent data){
super.onActivityResult(requestCode,resultCode,data);
callbackManager.onActivityResult(requestCode,resultCode,data);
}
public void facebookLogin(View v){
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile","user_friends"));
}
}
The code above crashes once i press the button, with the following error:
Process: com.example.adminn.facebooktest, PID: 8830
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=64206, result=-1, data=Intent { (has extras) }} to activity {com.example.adminn.facebooktest/com.example.adminn.facebooktest.MainActivity}: java.lang.NullPointerException: Argument 'context' cannot be null
at android.app.ActivityThread.deliverResults(ActivityThread.java:3626)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3669)
at android.app.ActivityThread.access$1300(ActivityThread.java:148)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1341)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
Caused by: java.lang.NullPointerException: Argument 'context' cannot be null
at com.facebook.internal.Validate.notNull(Validate.java:67)
at com.facebook.appevents.AppEventsLogger.<init>(AppEventsLogger.java:652)
at com.facebook.appevents.AppEventsLogger.newLogger(AppEventsLogger.java:417)
at com.facebook.login.LoginLogger.<init>(LoginLogger.java:67)
at com.facebook.login.LoginManager.getLogger(LoginManager.java:397)
at com.facebook.login.LoginManager.logCompleteLogin(LoginManager.java:415)
at com.facebook.login.LoginManager.onActivityResult(LoginManager.java:190)
at com.facebook.login.LoginManager$1.onActivityResult(LoginManager.java:140)
at com.facebook.internal.CallbackManagerImpl.onActivityResult(CallbackManagerImpl.java:82)
at com.example.adminn.facebooktest.MainActivity.onActivityResult(MainActivity.java:88)
at android.app.Activity.dispatchActivityResult(Activity.java:6161)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3622)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3669)
at android.app.ActivityThread.access$1300(ActivityThread.java:148)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1341)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
I have done some digging through the SDK's source code using breakpoints and i realized that the onActivityResult is being called twice (when i press the button and another one for no reason). The first time it goes smooth and retrieves the token and session information. When it finishes, the context field inside LoginManager.java is set to null. Since callbackManager.onActivityResult calls, at some point, logCompleteLogin, which in turn creates a LoginLogger based on the nulled context, the application crashes.
Why is onActivityResult being called twice? As far as i know, there is only another activity besides MainActivity, which is FacebookActivity.
回答1:
Both problems are solved and they are related.
What happens and i failed to understand was that the facebook button has an underlying event that triggers the login process. I set another event on MainActivity to act upon click. So, internally, what was happening was that, the facebookactivity was being created twice which lead to two calls to onActivityResult. The first call to onActivityResult leaves the internal state of LoginManager with a nulled context field (which was previously the MainActivity). A second call assumes that the context is not null, crashing the application if it is (there is a Validate verification internally).
Falling back to a previous version of the SDK worked because LogginManager.context was not being nullified when calling logInWithReadPermissions, rendering the second call "valid".
回答2:
In the latest v4.2.0 of the Facebook android sdk the NPE you are seeing looks to be a result of this commit.
It shouldn't be an issue in the next version of the sdk since a pull request has already been accepted which mitigates this issue pr430. And for now you could fallback to v4.1.2 of the sdk.
I'm not sure why the onActivityResult is called twice
来源:https://stackoverflow.com/questions/30736724/onactivityresult-called-twice