如何实现Razorpay API仅在支付成功时执行指定代码
问题根因
你当前的逻辑错误来自两点:
- Razorpay的
checkout.open()是异步调用,拉起支付页后不会阻塞等待支付结果,会立刻执行后续代码,所以你写在RazorPayAPI()调用后的跳转逻辑会在支付页刚弹出时就执行 - 你在
RazorPayAPI()方法内刚调用完open()就把flag设为true,此时支付流程才刚启动,完全没有拿到支付结果,这个标记逻辑完全无效
修复方案
核心原则:所有依赖支付成功结果的业务逻辑,必须全部放到Razorpay SDK提供的onPaymentSuccess回调中执行,不要写在拉起支付的调用链路后面
具体修改点:
- 删除按钮点击回调中,
RazorPayAPI(amount)调用之后的所有座位拼接、Intent跳转、flag判断代码,点击按钮时只做参数校验、金额计算、拉起支付页三个动作 - 移除无用的
flag变量,支付结果完全由SDK的两个回调方法分发,不需要自行维护状态标记 - 在
onPaymentSuccess回调中完成座位拼接、参数传值、跳转Ticket页面、finish当前页的逻辑,建议同时把回调返回的支付ID一并传到出票页留存 - 在
onPaymentError回调中仅做支付失败/取消的用户提示,不执行任何页面跳转、业务状态修改操作 - 修正
RazorPayAPI()方法:删除方法内flag=true的错误赋值,仅在JSON参数构造异常时弹出初始化失败提示即可
修正后的核心代码如下:
buttonDone.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (SeatAL.size()==24) { Toast.makeText(Book_Bus.this, "Select a minimum of 1 seat to pay", Toast.LENGTH_SHORT).show(); } else{ Toast.makeText(Book_Bus.this, "Redirecting...", Toast.LENGTH_SHORT).show(); int amount=count*Integer.valueOf(price)*100; count=0; // 仅执行拉起支付动作,后续逻辑全部移到支付成功回调 RazorPayAPI(amount); } } private void RazorPayAPI(int amount) { Checkout checkout=new Checkout(); checkout.setKeyID("<keyID>"); JSONObject object=new JSONObject(); try { object.put("name","<name>"); object.put("Description","Bus Ticket"); object.put("theme.color",bg_yellow); object.put("currency","INR"); object.put("amount",amount); object.put("prefill.contact","<phone>"); object.put("prefill.email","<email>"); checkout.open(Book_Bus.this,object); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(Book_Bus.this, "Payment initialization failed, please try again", Toast.LENGTH_SHORT).show(); } } }); @Override public void onPaymentSuccess(String paymentId) { // 仅支付成功会进入该方法,在此执行所有后续业务逻辑 Toast.makeText(this, "Payment Successful", Toast.LENGTH_SHORT).show(); // 拼接选中座位信息 String FinalSeats=""; for(int i=0;i<SeatsAL.size();i++){ FinalSeats+=SeatsAL.get(i); if(i!=SeatsAL.size()-1){ FinalSeats+=","; } } // 跳转出票页 Intent intent = new Intent(Book_Bus.this, Ticket.class); intent.putExtra("BusID", busRVModel.getBusID()); intent.putExtra("Source", busRVModel.getSrc()); intent.putExtra("Destination", busRVModel.getDest()); intent.putExtra("Timings", busRVModel.getTimings()); intent.putExtra("Seats", FinalSeats); intent.putExtra("PaymentID", paymentId); // 建议同步传递支付ID留存 startActivity(intent); finish(); } @Override public void onPaymentError(int errorCode, String errorMsg) { // 支付取消、失败都会进入该方法,仅做提示不跳转 Toast.makeText(getApplicationContext(), "Payment failed or cancelled, please try again", Toast.LENGTH_SHORT).show(); }
可选优化
- 点击完成按钮后可暂时将按钮置为不可点击,避免用户重复点击拉起多个支付页,在
onPaymentError回调中再恢复按钮可点击状态 - 座位选中状态、计数等业务数据的重置操作,建议放到
onPaymentSuccess中执行,避免用户支付取消/失败后返回页面需要重新选座 - 可以在
onPaymentSuccess中先把订单信息、支付ID提交到自有服务端存证,拿到服务端确认后再跳转到出票页,避免客户端回调伪造导致的订单异常
内容的提问来源于stack exchange,提问作者CypherZ
相关产品推荐
相关产品推荐

