空对象引用上的 BraintreeHttpClient.setBaseUrl(java.lang.String)

Posted

技术标签:

【中文标题】空对象引用上的 BraintreeHttpClient.setBaseUrl(java.lang.String)【英文标题】:BraintreeHttpClient.setBaseUrl(java.lang.String) on a null object reference 【发布时间】:2016-07-29 21:43:11 【问题描述】:

我正在使用 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.+'

【问题讨论】:

【参考方案1】:

全面披露:我为 Braintree 工作。

你是refreshing the client token every time you go through the checkout process as required吗?我看到你只是从服务器下载 Braintree 令牌,如果它是空的。

如果不了解您的 CreditCard 类或其 validateCard 方法,另一种可能是您传递给 Card.tokenize 的 CardBuilder 对象可能不是格式正确的。 ​

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

【讨论】:

是的,首先我在 onCreate() 中从服务器下载 Braintree 令牌,然后再次检查,如果它为空,则再次尝试下载令牌..并且卡格式正确.. ..因为这只崩溃的次数更少。 我们已经确定了问题并发布了修复程序。请将您的 Android v.zero SDK 版本升级到 2.2.4。有关详细信息,请参阅此处:github.com/braintree/braintree_android/issues/89

以上是关于空对象引用上的 BraintreeHttpClient.setBaseUrl(java.lang.String)的主要内容,如果未能解决你的问题,请参考以下文章

空对象引用上的 onActivityResult 数据

java.lang.NullPointerException:空对象引用上的 FloatingActionButton.setVisibility(int)'

空对象引用上的 void android.view.View.dispatchWindowVisibilityChanged(int)'

.getImage() 上的空对象引用 android [重复]

移动相机方法上的谷歌地图空对象引用[关闭]

空对象引用上的 TransitionSet ArrayList.size()