空对象引用上的 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)的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.NullPointerException:空对象引用上的 FloatingActionButton.setVisibility(int)'
空对象引用上的 void android.view.View.dispatchWindowVisibilityChanged(int)'