1

I'm building an app which consist of 1 main activity, and so far 5 fragments. One of the fragments, triggers an exception only when i rotate the device, from portrait to landscape. It works just fine, if I keep the fragment in portrait mode, and no issues exists in the other 4 either. The fragment consist entirely for the purpose of In App Purchases.
The 3 lines, that the Logcat complains about, doesn't make much sense to me, as they're very different, and doesn't really concern the same things.

Main activity:

public class Monthly_paid extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener, NavigationView.OnNavigationItemSelectedListener { private static final String TAG = "Monthly_paid"; private DrawerLayout drawer; private BottomNavigationView botnav; private AdView mAdView; private SharedPreferences mSharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_monthly_paid); mAdView = findViewById(R.id.adView); botnav = findViewById(R.id.navigation); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); drawer = findViewById(R.id.nav_drawer_layout); ActionBarDrawerToggle toogle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toogle); toogle.syncState(); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); NavigationView drawerNavigation = findViewById(R.id.nav_view); drawerNavigation.setNavigationItemSelectedListener(this); BottomNavigationView bottomNavigation = findViewById(R.id.navigation); bottomNavigation.setOnNavigationItemSelectedListener(this); //Sætter titlen i toolbar, til at være nedenstående string //Monthly_paid.this.setTitle(getText(R.string.app_name)); getSupportActionBar().setTitle(getText(R.string.app_name)); //Gør så Home er highlighted ved launch drawerNavigation.setCheckedItem(R.id.navigation_home); loadFragment(new MonthlyFragment()); //2 next lines is to find users FCM token, for firebase notifications // String myRefreshedToken = FirebaseInstanceId.getInstance().getToken(); // Log.d( "myRefreshedToken" , myRefreshedToken); } //Checker for shared preferences ved launch, og sætter dem som de skal være private void checkSharedPreferences(){ boolean adFree = mSharedPreferences.getBoolean(getString(R.string.remove_ads_key), false); Log.d(TAG, "Check SharedPref Start"); if (adFree == false){ Log.d(TAG, "Adfree Ikke Købt"); MobileAds.initialize(this, "@string/ads_test_id"); AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); mAdView.setVisibility(View.VISIBLE); }else{ Log.d(TAG, "Adfree Købt"); mAdView.setVisibility(View.INVISIBLE); } } private boolean loadFragment (Fragment fragment) { if(fragment != null){ getFragmentManager() .beginTransaction() .replace(R.id.fragment_container, fragment) .commit(); return true; } return false; } @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { Fragment fragment = null; switch (item.getItemId()){ // Bottom Navigation case R.id.navigation_monthly: fragment = new MonthlyFragment(); break; case R.id.navigation_hourly: fragment = new HourlyFragment(); break; case R.id.navigation_vat: fragment = new VATFragment(); break; //Navigation Drawer(Sidebar) case R.id.navigation_home: fragment = new MonthlyFragment(); //Gør bottom navigation bar synlig getSupportActionBar().setTitle(getText(R.string.app_name)); botnav.setVisibility(View.VISIBLE); break; /* case R.id.navigation_about_us: fragment = new AboutUsFragment(); break;*/ case R.id.navigation_documents: fragment = new PopUpPrivacy(); //Fjerner bottom navigation bar botnav.setVisibility(View.GONE); break; case R.id.navigation_premium: fragment = new InAppBilling(); botnav.setVisibility(View.GONE); break; } drawer.closeDrawer(GravityCompat.START); return loadFragment(fragment); } @Override public void onBackPressed(){ if (drawer.isDrawerOpen(GravityCompat.START)){ drawer.closeDrawer(GravityCompat.START); } else{ super.onBackPressed(); } } @Override public void onResume(){ super.onResume(); checkSharedPreferences(); //Sætter titlen i toolbar, til at være nedenstående string getSupportActionBar().setTitle(getText(R.string.app_name)); //Monthly_paid.this.setTitle(getText(R.string.app_name)); } } 

The troubled fragment:

public class InAppBilling extends Fragment implements PurchasesUpdatedListener, View.OnClickListener { private static final String TAG = "InAppBilling"; //In APP Produkter static final String ITEM_SKU_ADREMOVAL = "remove_ads_salary1"; private Button mButton; private Button back_Button; private String mAdRemovalPrice; private SharedPreferences mSharedPreferences; private SharedPreferences.Editor mEditor; private String purchaseToken; private BillingClient mBillingClient; private DrawerLayout drawer; private BottomNavigationView botnav; private FirebaseAnalytics mFirebaseAnalytics; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.inappbilling, container, false); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); mEditor = mSharedPreferences.edit(); //Sætter titlen i toolbar, til at være nedenstående string ((Monthly_paid)getActivity()).getSupportActionBar().setTitle(getText(R.string.title_premium)); mButton = v.findViewById(R.id.buy_button); v.findViewById(R.id.buy_button).setOnClickListener(this); mBillingClient = BillingClient.newBuilder(getActivity()).setListener(this).build(); mBillingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(int responseCode) { if (responseCode == BillingClient.BillingResponse.OK){ List skuList = new ArrayList<>(); skuList.add(ITEM_SKU_ADREMOVAL); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP); //Kører 2 nedenstående metoder, når activity åbnes - Tjekker om der er betalt for adFree checkPurchaseHistory(); checkPurchases(); checkSharedPreferences(); mBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) { //Processing the response if the code = OK, and skuDetailsList isn't = null(empty) if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null){ for (SkuDetails skuDetails : skuDetailsList){ String sku = skuDetails.getSku(); String price = skuDetails.getPrice(); if (ITEM_SKU_ADREMOVAL.equals(sku)){ mAdRemovalPrice = price; boolean adFree = mSharedPreferences.getBoolean(getString(R.string.remove_ads_key), false); if (adFree == false) { //Sætter teksten af købs knappen, til at være lig med prisen på at købe ad removal, hvis adRemoval ikke er købt mButton.setText(mAdRemovalPrice); } } } } } }); } } @Override public void onBillingServiceDisconnected() { // IMPLEMENT RETRY POLICY - TRY TO RESTART ON NEXT REQUEST BY CALLING startConnection() } }); return v; } @Override public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) { // Hvis bruger køber genstand if (responseCode == BillingClient.BillingResponse.OK && purchases != null){ for (Purchase purchase : purchases){ handlePurchase(purchase); Log.d(TAG, "onPurchaseUpdated() response: " + responseCode); String purchasedSku = purchase.getSku(); Log.i(TAG, "Purchased SKU: " + purchasedSku); this.purchaseToken = purchase.getPurchaseToken(); } }// Hvis bruger annullerer købet else if (responseCode == BillingClient.BillingResponse.USER_CANCELED){ Toast.makeText((getActivity()), R.string.purchase_cancelled, Toast.LENGTH_LONG).show(); Log.d(TAG, "USER CANCELED, Error code: " + responseCode); }/// Hvis bruger allerede ejer genstanden else if (responseCode == BillingClient.BillingResponse.ITEM_ALREADY_OWNED){ Log.d(TAG, "ITEM ALREADY OWNED"); mEditor.putBoolean((getResources().getString(R.string.remove_ads_key)), true); mEditor.commit(); mButton.setText(getResources().getString(R.string.ads_already_purchased)); mButton.setEnabled(false); mButton.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.button_rounded_gray)); } else{//Any other Error Log.d(TAG, "Billing Client ERROR Response code: " + responseCode); } } private void handlePurchase(Purchase purchase){ if (purchase.getSku().equals(ITEM_SKU_ADREMOVAL)){ Log.d(TAG, "AD Removal Købt!"); } } @Override public void onClick(View view) { if (view.getId() == R.id.buy_button) { BillingFlowParams flowParams = BillingFlowParams.newBuilder() // .setSkuDetails(skuDetails) .setSku(ITEM_SKU_ADREMOVAL) .setType(BillingClient.SkuType.INAPP) .build(); int responseCode = mBillingClient.launchBillingFlow(getActivity(), flowParams); } } private void checkSharedPreferences(){ boolean adFree = mSharedPreferences.getBoolean(getString(R.string.remove_ads_key), false); Log.d(TAG, "**********"); Log.d(TAG, "CHECK SHARED PREFERENCE START"); if (adFree == false){ Log.d(TAG, "IKKE KØBT ADFREE"); Log.d(TAG, "**********"); mButton.setText(R.string.ads_buy_button); mButton.setEnabled(true); mButton.setBackground(ContextCompat.getDrawable(getActivity(),R.drawable.button_rounded_green)); }else{ Log.d(TAG, "ADFREE KØBT"); Log.d(TAG, "**********"); mButton.setText(getResources().getString(R.string.ads_already_purchased)); mButton.setEnabled(false); mButton.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.button_rounded_gray)); } } private void checkPurchases(){ Purchase.PurchasesResult queryResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP); Log.d(TAG, "**********"); Log.d(TAG, "CHECK PURCHASES START"); if(queryResult.getPurchasesList() != null){ Log.d(TAG, "QUERY LISTE IKKE NULL"); if (queryResult.getPurchasesList().size() > 0) { Log.d(TAG, "Query Liste over 0"); for (Purchase result : queryResult.getPurchasesList()) { Log.d(TAG, "Bought OrderID: " + result.getOrderId()); Log.d(TAG, "Bought JSON: " + result.getOriginalJson()); Log.d(TAG, "Bought Token: " + result.getPurchaseToken()); if (result.getSku().equals(ITEM_SKU_ADREMOVAL)) { Log.d(TAG, "ADREMOVAL FUNDET I CHECK PURCHASES"); Log.d(TAG, "**********"); mEditor.putBoolean((getResources().getString(R.string.remove_ads_key)), true); mEditor.commit(); } else if (!result.getSku().equals(ITEM_SKU_ADREMOVAL)) { Log.d(TAG, "ADREMOVAL IKKE FUNDET I CHECK PURCHASES"); Log.d(TAG, "**********"); mEditor.putBoolean((getResources().getString(R.string.remove_ads_key)), false); mEditor.commit(); } } }else { mEditor.putBoolean((getResources().getString(R.string.remove_ads_key)), false); mEditor.commit(); } }else{ mEditor.putBoolean((getResources().getString(R.string.remove_ads_key)), false); mEditor.commit(); Log.d(TAG, "INTET FUNDET I QUERY LISTE"); Log.d(TAG, "**********"); } } private void checkPurchaseHistory(){ mBillingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, new PurchaseHistoryResponseListener() { @Override public void onPurchaseHistoryResponse(int responseCode, List<Purchase> purchasesList) { Log.d(TAG, "**********"); Log.d(TAG, "PURCHASE HISTORY START"); if (responseCode == BillingClient.BillingResponse.OK){ if (purchasesList != null){ Log.d(TAG, "PURCHASE HISTORY IKKE = NULL"); if (purchasesList.size() > 0){ for (Purchase result : purchasesList) { Log.d(TAG, "Bought JSON: " + result.getOriginalJson()); Log.d(TAG, "Bought Token: " + result.getPurchaseToken()); if (result.getSku().equals(ITEM_SKU_ADREMOVAL)) { Log.d(TAG, "ITEM REMOVAL FUNDET I PURCHASE HISTORY"); Log.d(TAG, "**********"); }else { Log.d(TAG, "ITEM REMOVAL IKKE FUNDET I PURCHASE HISTORY"); Log.d(TAG, "**********"); } } } } } } }); } @Override public void onResume() { super.onResume(); checkPurchases(); checkSharedPreferences(); ((Monthly_paid)getActivity()).getSupportActionBar().setTitle(getText(R.string.title_premium)); } // Gør det muligt at tracke brug af fragment via Firebase Analytics @Override public void onAttach(Context context) { super.onAttach(context); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mFirebaseAnalytics = FirebaseAnalytics.getInstance(getContext()); } } } 

Logcat Message:

java.lang.IllegalStateException: Fragment InAppBilling{bea3072} not attached to Activity at android.app.Fragment.getResources(Fragment.java:768) at studios.kundby.skatmomsberegner.InAppBilling.checkPurchases(InAppBilling.java:233) at studios.kundby.skatmomsberegner.InAppBilling.access$100(InAppBilling.java:53) at studios.kundby.skatmomsberegner.InAppBilling$1.onBillingSetupFinished(InAppBilling.java:102) at com.android.billingclient.api.BillingClientImpl$BillingServiceConnection$1.run(BillingClientImpl.java:1155) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7045) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964) 
2
  • Is there a reason you're using getFragmentManager() and the deprecated framework Fragments? Commented May 24, 2019 at 21:08
  • Actually no particular reason. This is a project that's been long in progress, I remember when i started, i followed a tutorial on fragments. My guess is that's where it originates from Commented May 24, 2019 at 21:39

1 Answer 1

1

There's two issues:

  1. You're unconditionally calling loadFragment(new MonthlyFragment()); in your Monthly_paid's onCreate(). Fragments automatically restore their state, so this should only be done if (savedInstanceState == null) to avoid overriding the Fragments being restored.

  2. You never call mBillingClient.endConnection(), so any asynchronous callbacks (like your onBillingSetupFinished()) aren't cancelled when your Fragment gets destroyed. Since you call startConnection() in onCreateView(), the logical place to put endConnection() is in onDestroyView().

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, it fixed my issues :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.