I am opening a Activity with ActivityResult and after buying a item successfully, I am closing the current activity which holds purching process and send data back. But Leak Canary catch a memory leak about BillingBroadcastReceiver. I init billing client OnCreate
and release onDestroy
.
Here is my init method which called in OnCreate
billingClient = BillingClient.newBuilder(this).setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(int responseCode) {
if (responseCode == BillingClient.BillingResponse.OK) {
// The billing client is ready. You can query purchases here.
loadProducts();
} else {
// Error
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
Timber.d("Connection Error");
}
});
Load Product infos when billingClient
is ready
private void loadProducts() {
if (billingClient.isReady()) {
List<String> skuList = new ArrayList<>(getViewModel().getSkuIdList());
SkuDetailsParams params = SkuDetailsParams.newBuilder().setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
if (responseCode == BillingClient.BillingResponse.OK) {
Timber.d("SkuList --> %s", skuDetailsList.size());
} else {
Timber.d("Can't querySkuDetailsAsync, responseCode: %s", responseCode);
}
}
});
} else {
Timber.d("Billing Client not Ready");
}
}
Here is my release method which called in OnDestroy
if (billingClient != null && billingClient.isReady()) {
billingClient.endConnection();
billingClient = null;
}
OnPurchaseUpdated I made a service call and close this activity based on service result.
public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
for (Purchase purchase : purchases) {
billingClient.consumeAsync(purchase.getPurchaseToken(), new ConsumeResponseListener() {
@Override
public void onConsumeResponse(int responseCode, String purchaseToken) {
if (responseCode == BillingClient.BillingResponse.OK && purchaseToken != null) {
Timber.d("onConsumeResponse --> %s", purchaseToken);
getViewModel().informPurchase(necessary data);
}
}
});
}
} else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
// Handle an error caused by a user canceling the purchase flow.
Timber.d("Billing Cancelled");
} else {
Timber.d("An Error Occured");
}
}
I am using latest library for in app purchase
implementation 'com.android.billingclient:billing:1.2.1'
After buying a item successfully and close recent activity, Leak Canary shows me this error. How can I avoid this memory leak?
endConnection
is not removing the reference to the activity thatsetListener(this)
is setting. Have you verified thatbillingClient.endConnection();
is actually being called by setting a breakpoint? – BertschebillingClient.endConnection();
called normally. I also callendConnection
method in observer ofinformPurchase
method for test purpose, still the same leak happens @CésarDeLaVega – Pina