-2

我正在使用 Braintree api 在应用程序中添加卡以进行付款。它工作正常,有时会随机崩溃,

这是我的堆栈跟踪,

E/AndroidRuntime: FATAL EXCEPTION: Thread-833
                                                          Process: cl.tempclick, PID: 29509
                                                          java.lang.NullPointerException: Attempt to invoke virtual method 'com.braintreepayments.api.internal.HttpClient com.braintreepayments.api.internal.BraintreeHttpClient.setBaseUrl(java.lang.String)' on a null object reference
                                                              at com.braintreepayments.api.BraintreeFragment.setConfiguration(BraintreeFragment.java:488)
                                                              at com.braintreepayments.api.BraintreeFragment$5.onConfigurationFetched(BraintreeFragment.java:415)
                                                              at com.braintreepayments.api.ConfigurationManager.getConfiguration(ConfigurationManager.java:46)
                                                              at com.braintreepayments.api.BraintreeFragment.fetchConfiguration(BraintreeFragment.java:412)
                                                              at com.braintreepayments.api.BraintreeFragment.waitForConfiguration(BraintreeFragment.java:458)
                                                              at com.braintreepayments.api.TokenizationClient.tokenize(TokenizationClient.java:72)
                                                              at com.braintreepayments.api.Card.tokenize(Card.java:29)
                                                              at cl.tk.ui.activities.sub_activity.AddPayment$UIThreadHandler$1.run(AddPayment.java:364)
                                                              at java.lang.Thread.run(Thread.java:818)

这是我的活动代码,

package cl.tk.ui.activities.sub_activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.braintreepayments.api.BraintreeFragment;
import com.braintreepayments.api.exceptions.InvalidArgumentException;
import    com.braintreepayments.api.interfaces.PaymentMethodNonceCreatedListener;
import com.braintreepayments.api.models.CardBuilder;
import com.braintreepayments.api.models.PaymentMethodNonce;

import cl.tk.R;
import cl.tk.controllers.constants.Constants;
import cl.tk.controllers.constants.Enums_String;
import cl.tk.controllers.listeners.ProcessedResult;
import cl.tk.controllers.rest_api.RetrofitAdapters;
import cl.tk.ui.activities.Register;
import cl.tk.ui.fragments.dialog.DTDialog;
import cl.tk.ui.iBAPViews.editext.pattern.PatternedEditText;
import cl.tk.utility.CreditCard;
import cl.tk.utility.CustomException;
import cl.tek.utility.GeneralFunctions;
import cl.tk.utility.MonthYearPicker;
import cl.tk.utility.Validation;
import cl.tk.utility.fonts.FontsManager;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;


public class AddPayment extends AppCompatActivity implements        View.OnClickListener,View.OnTouchListener, ProcessedResult,PaymentMethodNonceCreatedListener
{
private Handler uiThreadHandler;
private TextView tvExpiryDate;
//private EditText edCvv,ed_cardHOlderName,edZip;
private PatternedEditText edCardNumber;
private MonthYearPicker myp;
private String mClientToken=null;
private CreditCard creditCard =null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_payment);

    uiThreadHandler = new UIThreadHandler();
    initialze();

    downloadBraintreeTOken();
}

private void downloadBraintreeTOken()
{
    RetrofitAdapters.get().getBraintreeToken(new Callback<Response>() {
        @Override
        public void success(Response response, Response response2) {
            parseResult(response);
        }

        @Override
        public void failure(RetrofitError error) {
            uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.HIDEDIALOG);
            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
            message.obj = error.getLocalizedMessage();
            uiThreadHandler.sendMessage(message);
        }
    });
}

private void initialze()
{
    GeneralFunctions.setToolbarMsgIconHide(this, Constants.ToolbarConstants.PAYMENTS, true);

    Button buttonAdd=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_bt_addCard);
    buttonAdd.setOnClickListener(this);
    GeneralFunctions.setColorSelector(ContextCompat.getColor(this, R.color.color175), ContextCompat.getColor(this, R.color.color1A9), buttonAdd);

    TextView tv_defult=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_ct_default);
    tv_defult.setOnClickListener(this);

    FontsManager.initFormAssets(this, Enums_String.FontsNameLato.SEMIBOLD.toString());
    FontsManager.changeFonts(tv_defult);

    edCardNumber=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_ed_cardNumber);
    tvExpiryDate=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_tv_expiryDate);
    tvExpiryDate.setOnTouchListener(this);

    myp = new MonthYearPicker(this);
    myp.build(new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            tvExpiryDate.setText(myp.getSelectedMonth() + 1 + "/" + myp.getSelectedYear());
        }
    }, null);
}

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter(Enums_String.LocalReceiver.INTERENT.toString());
    LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}

@Override
public void onClick(View v) {
    switch (v.getId())
    {
        case R.id.payment_bt_addCard:
            uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.VALIDATION);
            break;
    }
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_UP)
    {
        if(v.getId()==R.id.payment_tv_expiryDate)
        {
            if(myp.pickerDialog != null && !myp.pickerDialog.isShowing())
                myp.pickerDialog.dismiss();
            myp.show();
        }
        return true;
    }
    return false;
}

@Override
public <IResponse, IMethod, IExtra> void processedResult(IResponse iResponse, IMethod iMethod, IExtra iExtra) {

}


@Override
public <IResponse, IMethod> void processedResult(IResponse iResponse, IMethod iMethod) {
    switch (iMethod.toString())
    {
        case Constants.CallbackConstants.VIEW_ERROR: {
            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SETERROR);
            message.obj=iResponse;
            uiThreadHandler.sendMessage(message);
        }
        break;
        case Constants.CallbackConstants.BACK:
            finish();
            break;
    }
}

@Override
public void onPaymentMethodNonceCreated(final PaymentMethodNonce paymentMethodNonce) {

}


private void setError(String errorMsg) {
    if (errorMsg.equalsIgnoreCase("cardNumber"))
        GeneralFunctions.setError(null,String.format(getString(R.string.ed_error_invalid),edCardNumber.getTag().toString()),edCardNumber);
    else if (errorMsg.equalsIgnoreCase("cardDate"))
        GeneralFunctions.setError(null,String.format(getString(R.string.ed_error_invalid),tvExpiryDate.getTag().toString()),tvExpiryDate);
}



private class UIThreadHandler extends Handler {
    @Override
    public void handleMessage(Message msg)
    {
        switch (msg.what) {
            case Constants.ActivityBasicsCode.CARDERROR:
                GeneralFunctions.setError((CustomException)msg.obj,null,null);
                break;
            case Constants.ActivityBasicsCode.SETERROR:
                setError(msg.obj.toString());
                break;
            case Constants.ActivityBasicsCode.SHOWTOAST:
            {
                String text=(String)msg.obj;
                GeneralFunctions.showToast(text,AddPayment.this);
            }
            break;
            case Constants.ActivityBasicsCode.HIDEDIALOG:
                GeneralFunctions.hideProgressDialog(Constants.DialogConstants.Transparent, AddPayment.this);
                break;
            case Constants.ActivityBasicsCode.SHOWDIALOG:
            {
                DTDialog dtDialog=DTDialog.newInstance();
                GeneralFunctions.showProgressDialog(dtDialog, Constants.DialogConstants.Transparent, AddPayment.this);
            }break;
            case Constants.ActivityBasicsCode.VALIDATION: {
                new Thread(new Runnable() {
                    @Override
                    public void run()
                    {
                        try {
                            if(Validation.validate(AddPayment.this)) {
                                creditCard = new CreditCard(GeneralFunctions.getText(edCardNumber),GeneralFunctions.getText(tvExpiryDate),AddPayment.this);

                                boolean validation = creditCard.validateCard();
                                if (validation) {
                                    if(mClientToken==null) {
                                        downloadBraintreeTOken();
                                        Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
                                        message.obj = getString(R.string.toast_payment_token);
                                        uiThreadHandler.sendMessage(message);
                                        return;
                                    }
                                    BraintreeFragment braintreeFragment= BraintreeFragment.newInstance(AddPayment.this, mClientToken);

                                    if(null==braintreeFragment)
                                    {
                                        Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
                                        message.obj = getString(R.string.toast_payment_fragment);
                                        uiThreadHandler.sendMessage(message);
                                        uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.SHOWDIALOG);
                                    }
                                    else {
                                        CardBuilder cardBuilder = new CardBuilder()
                                                .cardNumber(creditCard.getNumber().replaceAll("-", "").trim())
                                                .expirationDate(creditCard.getExpriyDate());
                                        com.braintreepayments.api.Card.tokenize(braintreeFragment, cardBuilder);   //On this line my app crashes randomly
                                    }
                                }
                            }
                        }catch (CustomException e)
                        {
                            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.CARDERROR);
                            message.obj=e;
                            uiThreadHandler.sendMessage(message);
                        } catch (InvalidArgumentException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
                break;
            }
        }
        super.handleMessage(msg);
    }
}

}

这是我的 gradle 版本,编译 'com.braintreepayments.api:braintree:2.+'

4

1 回答 1

0

全面披露:我为 Braintree 工作。

您是否在每次按要求完成结帐过程时刷新客户端令牌?我看到您只是从服务器下载 Braintree 令牌(如果它为空)。

在不了解您的 CreditCard 类或其 validateCard 方法的情况下,另一种可能是您传递给 Card.tokenize 的 CardBuilder 对象可能格式不正确。​</p>

如果您仍然遇到问题,请联系 Braintree 支持以帮助调试您的集成。

于 2016-04-11T18:03:52.937 回答