新的Android Billing v3文档和帮助程序代码在启动采购流程时使用startIntentSenderForResult()
。我想从Fragment
开始购买流程(并收到结果)。
例如,documentation建议调用
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
Integer.valueOf(0));
和helper code来电
mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,
mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
调用startIntentSenderForResult()
。
问题是,调用startIntentSenderForResult()
会导致onActivityResult()
在父Activity
上调用,而不是在调用它的Fragment
上调用IabHelper
onActivityResult()
居住)。
我可以在父Activity
中收到onActivityResult()
,然后手动调用Fragment
上的startIntentSenderForResult()
,但有没有办法调用Fragment
1}}从Fragment
直接将结果返回到onActivityResult()
的{{1}}?
答案 0 :(得分:36)
我建议两种解决方案:
1。)将IabHelper mHelper放在活动上,并从片段中调用IabHelper。
类似的东西:
要使用此解决方案,请在活动中将IabHelper声明为public,并使用方法从Fragment中调用启动器。
public class MyActivity extends Activity{
public IabHelper mHelper
public purchaseLauncher(){
mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,
mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
}
/*The finished, query and consume listeners should also be implemented in here*/
}
public class FragmentActivity extends Fragment{
MyActivity myAct = (MyActivity) getActivity();
myAct.purchaseLauncher();
}
2.)在onActivityResult中,调用包含IabHelper对象的相应片段。适当的片段可以具有对辅助对象的访问方法。
protected void onActivityResult(int requestCode, int resultCode,Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag("YourTag");
if (fragment != null)
{
((MyFragmentWithIabHelper)fragment).onActivityResult(requestCode, resultCode,data);
}
}
答案 1 :(得分:9)
1)您应该修改resultCode(RC_REQUEST)以将片段索引放入其中。
int rc_reqest = RC_REQUEST + ((getActivity().getSupportFragmentManager().getFragments().indexOf(this)+1)<<16) ;
mHelper.launchPurchaseFlow(getActivity(), sku, rc_reqest ,mPurchaseFinishedListener, payload);
2)在IabHelper.launchPurchaseFlow(...)
中change mRequestCode = requestCode
到
mRequestCode = requestCode&0xffff;
答案 2 :(得分:3)
关于LEO上面非常有用的第二个解决方案:
如果Google修复了startIntentSenderForResult的问题并且它现在正确地将onActivityResult调用路由到片段,那么这个解决方案应该是面向未来的,以便 片段的onActivityResult没有被调用两次。
我想提出LEO提出的以下修改方案。
在Fragment的父级Activity实现中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
boolean handled = false;
// The following is a hack to ensure that the InAppPurchasesFragment receives
// its onActivityResult call.
//
// For more information on this issue, read here:
//
// http://stackoverflow.com/questions/14131171/calling-startintentsenderforresult-from-fragment-android-billing-v3
//
// Note: If Google ever fixes the issue with startIntentSenderForResult() and
// starts forwarding on the onActivityResult to the fragment automatically, we
// should future-proof this code so it will still work.
//
// If we don't do anything and always call super.onActivityResult, we risk
// having the billing fragment's onActivityResult called more than once for
// the same result.
//
// To accomplish this, we create a method called checkIabHelperHandleActivityResult
// in the billing fragment that returns a boolean indicating whether the result was
// handled or not. We would just call Fragment's onActivityResult method, except
// its return value is void.
//
// Then call this new method in the billing fragment here and only call
// super.onActivityResult if the billing fragment didn't handle it.
if (inAppPurchasesFragment != null)
{
handled = inAppPurchasesFragment.checkIabHelperHandleActivityResult(requestCode, resultCode, data);
}
if (!handled)
{
super.onActivityResult(requestCode, resultCode, data);
}
}
然后在你的IAB片段实现中:
/**
* Allow the IabHelper to process an onActivityResult if it can
*
* @param requestCode The request code
* @param resultCode The result code
* @param data The data
*
* @return true if the IABHelper handled the result, else false
*/
public boolean checkIabHelperHandleActivityResult(int requestCode, int resultCode, Intent data)
{
return (iabHelper != null) && iabHelper.handleActivityResult(requestCode, resultCode, data);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!checkIabHelperHandleActivityResult(requestCode, resultCode, data))
{
super.onActivityResult(requestCode, resultCode, data);
}
}
答案 3 :(得分:2)
如果您有权访问它,我建议您在基本活动类中创建此问题的某种通用处理。
例如:
public abstract class BaseActivity extends Activity {
private List<ActivityResultHandler> mResultHandlers
= new ArrayList<ActivityResultHandler>();
public void registerActivityResultHandler(ActivityResultHandler resultHandler) {
mResultHandlers.add(resultHandler);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (ActivityResultHandler resultHandler : mResultHandlers) {
resultHandler.handle();
}
}
}
当然,您需要通过片段实现ActivityResultHandler接口,并在活动启动时注册它们。
答案 4 :(得分:2)
修改: android.support.v4.app.Fragment
现在包含startIntentSenderForResult()
的向后兼容版本,因此此答案已过时。
旧回答:
从支持库23.2.0开始,修改requestCode
不再有效:FragmentActivity
现在可以跟踪其片段发出的请求。我将此方法添加到托管FragmentActivity
的{{1}}(代码基于Fragment
):
FragmentActivity.startActivityFromFragment(Fragment, Intent, int, Bundle)
调用此选项时,只有传递的public void startIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) throws IntentSender.SendIntentException {
if (requestCode == -1) {
startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags);
return;
}
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
try {
Method method = FragmentActivity.class.getDeclaredMethod("allocateRequestIndex", Fragment.class);
method.setAccessible(true);
int requestIndex = (int) method.invoke(this, fragment);
startIntentSenderForResult(intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), fillInIntent, flagsMask, flagsValues, extraFlags);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
才会收到Fragment
来电。
答案 5 :(得分:2)
从SDK 24及更高版本开始,支持Fragment中还有一个startIntentSenderForResult方法,它可以按预期工作。 请注意,还有一个附加的Bundle参数,可以作为null传递。因此,最终代码将是:
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
Integer.valueOf(0), null);
当然,对于API 23及更低版本,我们仍然需要使用其他答案中描述的技巧。
答案 6 :(得分:2)
您需要将片段和数据传递给父活动,然后从父活动调用片段onActivityResult。
像这样 片段中的:
HomeActivity activity = (HomeActivity) getActivity();
activity.purchaseLauncher(this, mHelper, productDTO.getSku(), RC_REQUEST, mPurchaseFinishedListener, PAYLOAD);
&#13;
父活动中的
:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (storeFragment != null) {
storeFragment.onActivityResult(requestCode, resultCode, data);
}
}
public void purchaseLauncher(StoreFragment storeFragment, IabHelper mHelper, String sku, int requestCode, IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener, String payload) {
this.storeFragment = storeFragment;
mHelper.launchPurchaseFlow(this, sku, requestCode, mPurchaseFinishedListener, payload);
}
&#13;
答案 7 :(得分:1)
if (requestCode == RC_REQUEST)
{
Intent intent = new Intent(ContainerAvtivity.this,ContainerAvtivity.class);
startActivity(intent);
finish();
}
RC_REQUEST
与您用于启动购买流程的内容相同
在你的Activity的onActivityResult
中添加它。库存监听器将为你产生所需的结果。(我知道它是一个临时修复,但对我有用)。)
答案 8 :(得分:0)
您需要致电
super.onActivityResult(requestCode, resultCode, data);
在您的Activity和Fragment的onActivityResult的开头,将结果级联到片段。
在我的FragmentActivity中,这读为
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// No action here, call super to delegate to Fragments
super.onActivityResult(requestCode, resultCode, data);
}
答案 9 :(得分:0)
在我的情况下,我在Activity中执行了onActivityResult:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
并且在片段中相同,它使应用结算工作
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(ITEM_SKU, "onActivityResult handled by IABUtil.");
}
}
答案 10 :(得分:0)
如果您想要对您的片段进行回调,而不是从您的活动中调用super.onActivityResult()
。
这将调用您的片段onActivityResult()
。
不要忘记从片段上下文中调用startIntentSenderForResult
。
请勿使用活动上下文getActivity().startIntentSenderForResult