从片段调用 Google Play 游戏服务

Posted

技术标签:

【中文标题】从片段调用 Google Play 游戏服务【英文标题】:Calling Google Play Game Services from a fragment 【发布时间】:2013-06-03 04:41:36 【问题描述】:

我已在我的 android 应用程序中将一些 Google Play 游戏服务功能作为单独的 Activity 实现,我现在正尝试将我的代码重写为 (Action Bar Sherlock) 片段。我在片段中使用提供的 GameHelper 代码。

自动登录可以正常工作。用户发起的登录失败,因为 GameHelper 中的 StartResolutionForResult 调用返回到 Activity 的 onActivityResult 而不是片段。我已经使用 Log.D 验证了所有这些。我对此的理解是有限的——我应该怎么做才能解决这个问题?我尝试过传递不同的上下文,但 StartResolutionForResult 似乎只接受一个 Activity 作为其上下文。

【问题讨论】:

【参考方案1】:

Google Play 游戏服务 API 应该与 Activity 的生命周期相关联,而不是与 Fragment 的生命周期相关联。如果您的游戏逻辑在 Fragment 中,您可以在 Activity 上实现 onActivityResult 并从那里调用您的 Fragment。看看我们的Type A Number Challenge 示例,它不仅是一款令人兴奋和令人上瘾的游戏,还演示了如何处理片段。 Type A Number 中的每个屏幕都是一个片段,它们根据需要与 Activity 进行通信。

在这种特殊情况下,与游戏 API 的所有交互都是由 Activity 进行的。但是,您也可以让 Activity 将 GamesClient 对象交给 Fragment,以便它可以实现自己的逻辑。

在所有情况下,请记住不要在 Fragment 中保留对 GamesClient 的持久引用超过您需要的时间。最好在需要时从Activity(例如通过接口)查询它。这是为了防止它在 Activity 的生命周期中泄漏。

【讨论】:

谢谢布鲁诺。事实证明,该解决方案比我预期的要容易。我只是将以下代码添加到我的 onActivityResult 中:fred fragment=(fred)getSupportFragmentManager().findFragmentByTag("tab4"); fragment.onActivityResult(request, response, data); 为什么 API 不应该绑定到 Fragment 的生命周期?为什么是错的?有这方面的文档吗? @osrl 我也有同样的问题。我正在尝试将附近的共享功能封装在我的应用程序中的 DialogFragment 中,该功能仅在显示对话框时发布。无法为结果设置目标 Fragment 意味着我必须在需要此对话框的每个 Activity 中复制相同的 GoogleApiClient 代码,然后在客户端和需要它们的 Fragment 之间手动转发回调。【参考方案2】:

不再支持移位 1

您可以尝试通过Fragment 拨打电话

private static final int REQUEST_CHECK_SETTINGS = 0x1;

final ResolvableApiException rae = (ResolvableApiException) e;      
startIntentSenderForResult(rae.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null);

然后像这样在 Fragment 的 onActivtyResult 上捕获结果:

 @Override
    public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) 
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) 
            // Check for the integer request code originally supplied to startIntentSenderForResult().
            case REQUEST_CHECK_SETTINGS:
                switch (resultCode) 
                    case Activity.RESULT_OK:
                        // Do smth
                        break;
                    case Activity.RESULT_CANCELED:
                        // show Error
                        break;
                
                break;
        
    

【讨论】:

【参考方案3】:

您可以将onActivityResult 调用转发到片段,如下所示:

我们应该将请求代码按位移动 16 位。

public static final int REQUEST_CHECK_SETTINGS = 1<<16; //shifted 1 16 bits

将此添加到拥有该片段的活动中。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);

注意:我从 FragmentActivity 中onActivityResult 的源代码中发现了这一点。它将 requestCode 向右移动 16 位。

/**
 * Dispatch incoming result to the correct fragment.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    mFragments.noteStateNotSaved();
    int index = requestCode>>16;
    if (index != 0) 
        index--;
        final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
        if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) 
            Log.w(TAG, "Activity result fragment index out of range: 0x"
                    + Integer.toHexString(requestCode));
            return;
        
        final List<Fragment> activeFragments =
                mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
        Fragment frag = activeFragments.get(index);
        if (frag == null) 
            Log.w(TAG, "Activity result no fragment exists for index: 0x"
                    + Integer.toHexString(requestCode));
         else 
            frag.onActivityResult(requestCode&0xffff, resultCode, data);
        
        return;
    

    super.onActivityResult(requestCode, resultCode, data);

注意 2:如果有人能告诉我为什么使用这种方法会是一种不好的方法,我会很高兴

【讨论】:

【参考方案4】:

我不确定 Games 的 API 与 Nearby 相比有多相似(我认为这应该可以),但是在为 Nearby 创建 GoogleApiClient 时,我发现在错误回调(状态、ConnectionResult)中传递的对象很方便可打包。所以我创建了一个可以启动的 Activity 来处理这些错误,然后将它收到的任何结果传回给调用者。

https://gist.github.com/damien5314/c13ce47bca035c517dfbdfb2af488a73

用法:

Nearby.Messages.publish(mNearbyApi, mMessage)
        .setResultCallback(new ResultCallback<Status>() 
            @Override
            public void onResult(@NonNull Status status) 
                Log.d(TAG, "Nearby publish result: " + getStatusCodeString(status.getStatusCode()));
                if (status.getStatusCode() > 0) 
                    Intent intent = ResolveErrorActivity.buildIntent(getContext(), status);
                    startActivityForResult(intent, ResolveErrorActivity.REQUEST_RESOLVE_ERROR);
                
            
        );

只要你从一个 Fragment 调用startActivityForResult,它就应该像往常一样得到结果。

【讨论】:

以上是关于从片段调用 Google Play 游戏服务的主要内容,如果未能解决你的问题,请参考以下文章

Google play 游戏服务再次显示来自 google+ 的登录屏幕

应用程序未正确配置为使用 Google Play 服务

从 Google Play 游戏服务获取用户分数?

Google play 游戏服务 - 从应用程序以横向模式启动 google+ 登录流程

Google Play 游戏:UnlockAchievement 调用时出现 401 错误

Google Play 游戏服务登录回调