问题
I have implemented some Google Play Game Services features in my Android app as a separate Activity and I am now trying to rewrite my code as an (Action Bar Sherlock) fragment. I am using the supplied GameHelper code in my fragment.
An auto sign in works correctly. A user initiated sign in fails because the StartResolutionForResult call in GameHelper returns to the Activity's onActivityResult rather than to the fragment. I have verified all this by using Log.D . My understanding of this is limited - what should I do to fix this ? I have tried passing a different context but the StartResolutionForResult seems to only accept an Activity as its context.
回答1:
The Google Play game services API should be tied to an Activity's lifecycle, not a Fragment's lifecycle. If your game logic is in a Fragment, you can implement onActivityResult on the Activity and call your Fragment from there. Take a look at our Type A Number Challenge sample, which, apart from being a highly exciting and addictive game</sarcasm>, demonstrates how to deal with Fragments. Each screen in Type A Number is a fragment, and they communicate with the Activity as needed.
In this particular case, all the interaction with the games API is made by the Activity. However, you could just as well make the Activity hand the GamesClient
object to the Fragment so that it could implement its own logic.
In all cases, remember not to keep a persistent reference to GamesClient
in the Fragment for longer than you need. It's probably best to query it from the Activity
(via an interface, for instance) whenever you need it. This is to prevent it from leaking during the Activity's lifecycle.
回答2:
Shifting 1<<16 is not supported anymore.
You can try call it from your 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);
And catch result on Fragment's onActivtyResult
like this:
@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:
You can forward the onActivityResult
call to the fragment like this:
We should bitwise shift a request code by 16 bits.
public static final int REQUEST_CHECK_SETTINGS = 1<<16; //shifted 1 16 bits
Add this to the activity who owns the fragment.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
Note: I've figured this out from the source code of onActivityResult
in FragmentActivity. It is shifting the requestCode 16 bits to the right.
/**
* 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);
}
Note 2: I would be glad if someone could tell me why using this method would be a bad approach
回答4:
I'm not sure how similar the API for Games is compared to Nearby (I think this should work), but when creating a GoogleApiClient for Nearby, I found that the objects passed in error callbacks (Status, ConnectionResult) are conveniently Parcelable. So I created an Activity that can be launched to handle these errors, and then pass whatever result it receives back to the caller.
https://gist.github.com/damien5314/c13ce47bca035c517dfbdfb2af488a73
Usage:
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);
}
}
});
As long as you call startActivityForResult
from a Fragment, it should get the result as usual.
来源:https://stackoverflow.com/questions/16974527/calling-google-play-game-services-from-a-fragment