onActivityResult 调用了两次

onActivityResult called twice

我有一个简单的 activity,带有一个用于登录的 facebook 按钮(使用 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"));

    }
}

一旦我按下按钮,上面的代码就会崩溃,并出现以下错误:

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.access00(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.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.access00(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)

我使用断点对 SDK 的源代码进行了一些挖掘,我意识到 onActivityResult 被调用了两次(当我无缘无故地按下按钮和另一个按钮时)。第一次顺利并检索令牌和会话信息。完成后,LoginManager.java 中的上下文字段将设置为空。由于 callbackManager.onActivityResult 在某些时候调用了 logCompleteLogin,后者又根据空上下文创建了一个 LoginLogger,因此应用程序崩溃了。

为什么 onActivityResult 被调用了两次?据我所知,除了MainActivity,还有一个activity,就是FacebookActivity。

在 Facebook android SDK 的最新 v4.2.0 中,您看到的 NPE 看起来是 this 提交的结果。

在下一个版本的 sdk 中这应该不是问题,因为拉取请求已经被接受,从而缓解了这个问题 pr430。现在您可以回退到 sdk 的 v4.1.2。

我不确定为什么 onActivityResult 被调用了两次

两个问题都解决了,而且它们是相关的。

发生了什么但我未能理解的是 facebook 按钮有一个触发登录过程的基础事件。我在 MainActivity 上设置了另一个事件以在单击时起作用。所以,在内部,发生的事情是,facebookactivity 被创建了两次,这导致了对 onActivityResult 的两次调用。对 onActivityResult 的第一次调用使 LoginManager 的内部状态留下一个空的上下文字段(以前是 MainActivity)。第二次调用假定上下文不为空,如果为空则应用程序崩溃(内部有 Validate 验证)。

回退到以前版本的 SDK 是有效的,因为 LogginManager.context 在调用 logInWithReadPermissions 时没有被取消,呈现第二个调用 "valid"。