55 votes

Appel de startIntentSenderForResult depuis Fragment (Android Billing v3)

Le nouveau Android de Facturation v3 documentation et l'aide de code utilise startIntentSenderForResult() lors du lancement d'un achat de flux. Je veux commencer un achat de flux (et de recevoir le résultat) à partir d'un Fragment.

Par exemple, la documentation suggère d'appeler

startIntentSenderForResult(pendingIntent.getIntentSender(),
    1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
    Integer.valueOf(0));

et le helper code appels

mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,   
    mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

qui demande startIntentSenderForResult().

Le problème est, en appelant startIntentSenderForResult() provoque onActivityResult() d'être appelé sur le parent Activity plutôt que sur l' Fragment qu'il a été appelé à partir (où l' IabHelper réside).

Je pourrais recevoir l' onActivityResult() dans le parent de l' Activity manuellement, puis appeler l' onActivityResult() sur le Fragment, mais est-il un moyen de faire un appel à l' startIntentSenderForResult() d'un Fragment qui renvoie le résultat directement à l' Fragments' onActivityResult()?

36voto

LEO Points 526

Je suggère deux solutions:

1.) Mettez l’IabHelper mHelper sur l’activité et appelez le IabHelper à partir du fragment.

Quelque chose comme:

 MyActivity myAct = (MyActivity) getActivity();
myAct.mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,   
     mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
 

2.) Dans onActivityResult, appelez le fragment approprié contenant l'objet IabHelper. Le fragment approprié peut avoir une méthode d'accès à l'objet d'assistance.

 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);
    } 
}
 

9voto

Timur Points 11

1) Vous devez modifier votre code de résultat (RC_REQUEST) pour y mettre un index de fragment.

 int rc_reqest = RC_REQUEST +  ((getActivity().getSupportFragmentManager().getFragments().indexOf(this)+1)<<16)  ;      
mHelper.launchPurchaseFlow(getActivity(), sku, rc_reqest ,mPurchaseFinishedListener, payload);
 

2) dans IabHelper.launchPurchaseFlow (...)

 change mRequestCode = requestCode
 

à

 mRequestCode = requestCode&0xffff;
 

3voto

Michael Krause Points 1106

Quant à LEO est très utile 2ème solution ci-dessus:

Si Google jamais résout le problème avec startIntentSenderForResult, et il est maintenant correctement les routes de la onActivityResult appel à la fragment, alors cette solution doit être paré pour l'avenir, de sorte que le fragment de la onActivityResult n'est pas appelée deux fois.

Je voudrais proposer est la suivante modifiée solution proposée par LEO.

Dans le Fragment parent de la mise en œuvre des Activités:

@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);
    }
}

Puis dans votre IAB Fragment de la mise en œuvre:

/**
 * 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);
    }
}

2voto

user3925823 Points 11

Je suggère de créer une sorte de traitement générique de ce problème dans votre classe d'activité de base si vous y avez accès.

Par exemple:

 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();
        }
    }
}
 

Bien sûr, vous devrez implémenter l'interface ActivityResultHandler par vos fragments et les enregistrer au démarrage de l'activité.

-1voto

user2262061 Points 11

Vous devez appeler

 super.onActivityResult(requestCode, resultCode, data);
 

au début de votre activité et de vos fragments onActivityResult pour cascader les résultats avec les fragments.

Dans mon FragmentActivity, cela se lit comme

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // No action here, call super to delegate to Fragments
    super.onActivityResult(requestCode, resultCode, data);
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X