I have a single activity application (java) and one of the fragments contains Subscription buttons. I'm setting up the Google Play Billing Library but when I set up the following:
private BillingClient billingClient = BillingClient.newBuilder(getActivity())
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
I get this error:
java.lang.IllegalArgumentException: Please provide a valid Context.
at com.android.billingclient.api.BillingClient$Builder.build
I also tried
getContext()
and
getActivity.getApplicationContext()
but didn't work either. Neither did requireContext().
What context should I pass if I'm inside a fragment?
UPDATE:
The subscription fragment is called by the SignUpFragemnt:
public class SignUpFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sign_up, container, false);
Button nextButton = v.findViewById(R.id.nextButton);
nextButton.setOnClickListener(v1 -> {
Navigation.findNavController(v1).navigate(R.id.subscriptionV3Fragment);
});
return v;
}
}
And this is Subscription Fragment:
public class SubscriptionV3Fragment extends Fragment implements View.OnClickListener {
private static final String TAG = "SubscriptionV3Fragment";
SkuDetails monthlyDetails;
SkuDetails annualDetails;
Context context = getActivity();
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
}
};
private BillingClient billingClient = BillingClient.newBuilder(requireContext())
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_subscription_v3, container, false);
startConnection();
Button monthlySubscribe = v.findViewById(R.id.monthlySubscribeBut);
monthlySubscribe.setOnClickListener(this);
return v;
}
private void startConnection() {
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingServiceDisconnected() {
// PENDING
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
querySubscriptionProducts();
}
}
});
}
private void querySubscriptionProducts() {
List<String> skuList = new ArrayList<>();
skuList.add("sub_monthly");
skuList.add("sub_annual");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS);
billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
Log.d(TAG, "onSkuDetailsResponse: " + list);
}
});
}
}
The problem is not the context
in this case, the problem is where it is being access from. When this part of your code is called, other methods of FragmentLifeCycle are still in work.
private BillingClient billingClient = BillingClient.newBuilder(requireContext())
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
I would suggest you move it down inside after OnCreateView()
or even better inside onViewCreated()
Just assign it up top
private BillingClient billingClient;
Then inside onViewCreated()
you can do this
billingClient = BillingClient.newBuilder(requireContext())
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();