Stripe-android: Rx-java support

Created on 18 Jul 2015  Â·  9Comments  Â·  Source: stripe/stripe-android

I want to put my credit card creation inside an observable for testing purposes: and I get:

java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
            at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:146)
            at android.app.ActivityThread.main(ActivityThread.java:5694)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.ExceptionInInitializerError
            at com.stripe.android.Stripe$1.create(Stripe.java:22)
            at com.stripe.android.Stripe.createToken(Stripe.java:144)
            at com.stripe.android.Stripe.createToken(Stripe.java:127)
            at com.stripe.android.Stripe.createToken(Stripe.java:131)
            at com.pickupnow.customer.model.payment.PaymentService.lambda$createToken$59(PaymentService.java:30)
            at com.pickupnow.customer.model.payment.PaymentService.access$lambda$0(PaymentService.java)
            at com.pickupnow.customer.model.payment.PaymentService$$Lambda$1.call(Unknown Source)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable.unsafeSubscribe(Observable.java:7531)
            at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
            at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:200)
            at android.os.Handler.<init>(Handler.java:114)
            at com.stripe.android.compat.AsyncTask$InternalHandler.<init>(AsyncTask.java:579)
            at com.stripe.android.compat.AsyncTask$InternalHandler.<init>(AsyncTask.java:579)
            at com.stripe.android.compat.AsyncTask.<clinit>(AsyncTask.java:189)
            at com.stripe.android.Stripe$1.create(Stripe.java:22)
            at com.stripe.android.Stripe.createToken(Stripe.java:144)
            at com.stripe.android.Stripe.createToken(Stripe.java:127)
            at com.stripe.android.Stripe.createToken(Stripe.java:131)
            at com.pickupnow.customer.model.payment.PaymentService.lambda$createToken$59(PaymentService.java:30)
            at com.pickupnow.customer.model.payment.PaymentService.access$lambda$0(PaymentService.java)
            at com.pickupnow.customer.model.payment.PaymentService$$Lambda$1.call(Unknown Source)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable$1.call(Observable.java:144)
            at rx.Observable$1.call(Observable.java:136)
            at rx.Observable.unsafeSubscribe(Observable.java:7531)
            at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
            at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

When I execute:

public Observable<String> createToken(String number, int month, int year, String cvc, String zip) {
        return Observable.create(subscriber -> {
            Card card = new Card(number, month, year, cvc);
            card.setAddressZip(zip);

            if (card.validateCard()) {
                try {
                    Stripe stripe = new Stripe(BuildConfig.STRIPE_TOKEN);

                    stripe.createToken(card, new TokenCallback() {
                        @Override
                        public void onSuccess(final Token token) {
                            subscriber.onNext(token.getId());
                            subscriber.onCompleted();
                        }

                        @Override
                        public void onError(Exception e) {
                            subscriber.onError(e);
                        }
                    });
                } catch (AuthenticationException e) {
                    subscriber.onError(e);
                }
            } else {
                subscriber.onError(new InvalidCardException("Invalid card values"));
            }
        });
    }

Most helpful comment

@evelyne24 It would be preferable to provide a sync method or a RxJava hook/extension (See retrofit etc)

All 9 comments

@danielgomezrico see the yoyo/stripe-android fork

@chrisjenx You mean this one? https://github.com/justyoyo/stripe-android ?

Yeah, we added a sync method so we can wrap it with RX calls

On Sun, 19 Jul 2015 05:48 Daniel Gomez Rico [email protected]
wrote:

@chrisjenx https://github.com/chrisjenx You mean this one?
https://github.com/justyoyo/stripe-android

—
Reply to this email directly or view it on GitHub
https://github.com/stripe/stripe-android/issues/47#issuecomment-122625498
.

:+1: thanks

That's because the AsyncTask execute() needs to be called on the main thread. I'm imagining that you're probably calling subscribeOn() with a different thread or this observable is part of a bigger chain and at the end you call subscribeOn() a background thread. This could be solved (without using the Stripe fork) by simply making this observable call subscribeOn() the main thread so that it starts the async task where it needs.

@evelyne24 but that will not let me wrap it inside "my own rx api" for my project.

@evelyne24 It would be preferable to provide a sync method or a RxJava hook/extension (See retrofit etc)

Is there any solution to this? I'm having 3 network calls after Stripe token is created and it would be nice to wrap them all up into a single call :)
EDIT: Would it be possible to copy this project, replace the asnyc call with a sync call and instead of using Android Stripe library, use regular Stripe Java library?

@tomislavturcic, @chrisjenx, @caipivara, @evelyne24, and @chrisjenx

I'm happy to announce that we now have a synchronous createToken method (createTokenSynchronous) in Stripe.java, and an example of using it with rxJava hooks in the example project.

I haven't yet shipped a new version to maven central, but I'll be doing that very shortly. In the meantime, the code is in the repo if you'd like to look at it!

Was this page helpful?
0 / 5 - 0 ratings