我正在构建一个包含1个主要活动和5个片段的应用程序。片段之一仅在我旋转设备(从纵向到横向)时触发异常。如果我将片段保持为纵向模式,并且在其他4个组件中均不存在问题,则它工作得很好。
该片段完全出于应用内购买的目的而组成。
Logcat抱怨的3行对我来说意义不大,因为它们非常不同,并且实际上并没有关注相同的事物。
主要活动:
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));
}
}
麻烦的片段:
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消息:
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)
答案 0 :(得分:0)
有两个问题:
您正在无条件调用loadFragment(new MonthlyFragment());
的{{1}}中的Monthly_paid
。片段会自动恢复其状态,因此只能onCreate()
执行此操作,以避免覆盖要还原的片段。
您永远不会调用mBillingClient.endConnection()
,因此当您的Fragment被销毁时,任何异步回调(例如您的if (savedInstanceState == null)
)都不会被取消。由于您在onBillingSetupFinished()
中调用startConnection()
,因此放置onCreateView()
的逻辑位置在endConnection()
中。