英文:
Android subscription purchase AccountHold is null
问题
以下是翻译好的部分:
我正在使用官方的Google示例代码进行用户订阅 play-billing-sample。在切换Google账号时(我的手机上注册了两个Google账号作为测试账号以测试购买),我在检查账号保留时遇到了空指针异常。
- 我成功地登录了第一个账号,并购买了基本或高级订阅。
- 当我切换到第二个账号时,我遇到了下面的错误:
java.lang.NullPointerException: 尝试在空对象引用上调用虚拟方法 'boolean java.lang.Boolean.booleanValue()',位于 com.pishimishi.test.classytaxijava.billing.BillingUtilities.isAccountHold(BillingUtilities.java:151)
BillingUtilities.java:
/**
* 如果应该显示账号保留,则返回true。
*/
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
!subscription.isEntitlementActive &&
subscription.isAccountHold &&
!subscription.subAlreadyOwned;
}
SubscriptionStatus.java:
/**
* 本地订阅数据。这在数据库中以磁盘存储。
*/
@Entity(tableName = "subscriptions")
public class SubscriptionStatus {
// ...(省略了类的其他部分)
@Override
public String toString() {
return "SubscriptionStatus{" +
"primaryKey=" + primaryKey +
", subscriptionStatusJson='" + subscriptionStatusJson + '\'' +
", subAlreadyOwned=" + subAlreadyOwned +
", isLocalPurchase=" + isLocalPurchase +
", sku='" + sku + '\'' +
", purchaseToken='" + purchaseToken + '\'' +
", isEntitlementActive=" + isEntitlementActive +
", willRenew=" + willRenew +
", activeUntilMillisec=" + activeUntilMillisec +
", isFreeTrial=" + isFreeTrial +
", isGracePeriod=" + isGracePeriod +
", isAccountHold=" + isAccountHold +
'}';
}
}
我不明白为什么会出现空指针异常。或者如果我们是从服务器获取的,为什么在第一个账号上没有出现这个问题(我甚至测试了将第一个账号的购买暂停),而它却起作用。
附注:最初在我的Play控制台中,账号保留功能是未激活的,但后来我激活了账号保留和账号暂停功能。但是在切换到第二个Google账号后,我仍然得到相同的错误。
英文:
I am using official google example code for user subscription play-billing-sample. I get nullpointexception on checking the account hold when switching google accounts (my phone has two google accounts registered as test accounts to test the purchases).
- I log into the first account without any problems and purchase basic or premium subscriptions
- when I switch to the second account, I get the error below:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference at com.pishimishi.test.classytaxijava.billing.BillingUtilities.isAccountHold(BillingUtilities.java:151)
BillingUtilities.java:
/**
* Returns true if account hold should be shown.
*/
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
!subscription.isEntitlementActive &&
subscription.isAccountHold &&
!subscription.subAlreadyOwned;
}
and SubscriptionStatus.java:
/**
* Local subscription data. This is stored on disk in a database.
*/
@Entity(tableName = "subscriptions")
public class SubscriptionStatus {
public class SubscriptionStatusList {
@Nullable
@SerializedName("subscriptions")
List<SubscriptionStatus> subscriptionStatuses;
SubscriptionStatusList(@Nullable List<SubscriptionStatus> subscriptionStatuses) {
this.subscriptionStatuses = subscriptionStatuses;
}
}
public static final String SUBSCRIPTIONS_KEY = "subscriptions";
public static final String SKU_KEY = "sku";
public static final String PURCHASE_TOKEN_KEY = "purchaseToken";
public static final String IS_ENTITLEMENT_ACTIVE_KEY = "isEntitlementActive";
public static final String WILL_RENEW_KEY = "willRenew";
public static final String ACTIVE_UNTIL_MILLISEC_KEY = "activeUntilMillisec";
public static final String IS_FREE_TRIAL_KEY = "isFreeTrial";
public static final String IS_GRACE_PERIOD_KEY = "isGracePeriod";
public static final String IS_ACCOUNT_HOLD_KEY = "isAccountHold";
// Local fields
@PrimaryKey(autoGenerate = true)
public int primaryKey = 0;
@Nullable
public String subscriptionStatusJson;
public boolean subAlreadyOwned;
public boolean isLocalPurchase;
// Remote fields
@Nullable
public String sku;
@Nullable
public String purchaseToken;
public Boolean isEntitlementActive;
public Boolean willRenew;
public Long activeUntilMillisec = 0L;
public Boolean isFreeTrial;
public Boolean isGracePeriod;
public Boolean isAccountHold;
/**
* Parse subscription data from Map and return null if data is not valid.
*/
@Nullable
public static List<SubscriptionStatus> listFromMap(Map<String, Object> map) {
List<SubscriptionStatus> subscriptions = new ArrayList<>();
List<Map<String, Object>> subList = null;
if (map.get(SUBSCRIPTIONS_KEY) instanceof ArrayList) {
subList = (ArrayList) map.get(SUBSCRIPTIONS_KEY);
}
if (subList == null) {
return null;
}
for (Map<String, Object> subStatus : subList) {
SubscriptionStatus subscriptionStatus = new SubscriptionStatus();
subscriptionStatus.sku = (String) subStatus.get(SKU_KEY);
subscriptionStatus.purchaseToken = (String) subStatus.get(PURCHASE_TOKEN_KEY);
subscriptionStatus.isEntitlementActive =
(Boolean) subStatus.get(IS_ENTITLEMENT_ACTIVE_KEY);
subscriptionStatus.willRenew = (Boolean) subStatus.get(WILL_RENEW_KEY);
subscriptionStatus.activeUntilMillisec =
(Long) subStatus.get(ACTIVE_UNTIL_MILLISEC_KEY);
subscriptionStatus.isFreeTrial = (Boolean) subStatus.get(IS_FREE_TRIAL_KEY);
subscriptionStatus.isGracePeriod = (Boolean) subStatus.get(IS_GRACE_PERIOD_KEY);
subscriptionStatus.isAccountHold = (Boolean) subStatus.get(IS_ACCOUNT_HOLD_KEY);
subscriptions.add(subscriptionStatus);
}
return subscriptions;
}
/**
* Parse subscription data from String and return null if data is not valid.
*/
@Nullable
public static List<SubscriptionStatus> listFromJsonString(String dataString) {
Gson gson = new Gson();
try {
SubscriptionStatusList subscriptionStatusList =
gson.fromJson(dataString, SubscriptionStatusList.class);
if (subscriptionStatusList != null) {
return subscriptionStatusList.subscriptionStatuses;
} else {
return null;
}
} catch (JsonSyntaxException e) {
return null;
}
}
/**
* Create a record for a subscription that is already owned by a different user.
*
* The server does not return JSON for a subscription that is already owned by
* a different user, so we need to construct a local record with the basic fields.
*/
public static SubscriptionStatus alreadyOwnedSubscription(String sku, String purchaseToken) {
SubscriptionStatus subscriptionStatus = new SubscriptionStatus();
subscriptionStatus.sku = sku;
subscriptionStatus.purchaseToken = purchaseToken;
subscriptionStatus.isEntitlementActive = false;
subscriptionStatus.subAlreadyOwned = true;
return subscriptionStatus;
}
@Override
public String toString() {
return "SubscriptionStatus{" +
"primaryKey=" + primaryKey +
", subscriptionStatusJson='" + subscriptionStatusJson + '\'' +
", subAlreadyOwned=" + subAlreadyOwned +
", isLocalPurchase=" + isLocalPurchase +
", sku='" + sku + '\'' +
", purchaseToken='" + purchaseToken + '\'' +
", isEntitlementActive=" + isEntitlementActive +
", willRenew=" + willRenew +
", activeUntilMillisec=" + activeUntilMillisec +
", isFreeTrial=" + isFreeTrial +
", isGracePeriod=" + isGracePeriod +
", isAccountHold=" + isAccountHold +
'}';
}
}
I don't understand it why I have to get NPE. Or if we get if from the server, why don't I get it with the first account (I even tested putting the purchase on pause for the first account) and it works.
PS. Initially in my play console, Account hold feature was not active, but later on, I activated the account hold and account pause feature. But still I get the same error just after switching to the second google account.
答案1
得分: 0
每当 Java 在 if 语句 中使用 Boolean
对象时,它会通过 Boolean.booleanValue()
方法将其解包为基本类型 boolean
。
要解决这个问题,你需要将 isAccountHold
和 isEntitlementActive
的类型从 Boolean 更改为 boolean。
如果这些字段必须保持 Boolean 类型,那么在使用之前先检查它们是否为 null:
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
(subscription.isEntitlementActive == null || !subscription.isEntitlementActive) &&
(subscription.isAccountHold != null || subscription.isAccountHold) &&
!subscription.subAlreadyOwned;
}
英文:
Every time when Java uses Boolean
object in if statement it unwraps it to primitive which is boolean
type with Boolean.booleanValue()
method.
To fix the issue you have to change isAccountHold
and isEntitlementActive
types from Boolean to boolean.
If those fields have to be Boolean type then check them for null before:
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
(subscription.isEntitlementActive == null || !subscription.isEntitlementActive) &&
(subscription.isAccountHold != null || subscription.isAccountHold) &&
!subscription.subAlreadyOwned;
}
专注分享java语言的经验与见解,让所有开发者获益!
评论