0

У меня есть специальный прецедент, где мне нужно переключаться между двумя фрагментами. Проблема, с которой я сталкиваюсь, заключается в том, что для второго фрагмента мне нужно сохранить его состояние, и единственное, что, похоже, работает для этого, - это добавить его в BackStack.Фрагмент backstack и toggle

Я полагаюсь на менеджера фрагмента поддержки для замены фрагментов:

public void toggle() { 
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 
    if (fragment instanceof FragmentB && null != fragmentA) { 
     // fragment B is visible - we should show fragment A 

     getSupportFragmentManager().beginTransaction() 
            .setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out, 
                 R.anim.frag_fade_in, R.anim.frag_fade_out) 
            .replace(R.id.fragment_container, fragmentA) 
            .commit(); 
    } else if (fragment instanceof FragmentA && null != fragmentB) { 
     // fragment A is visible - we should show fragment B 

     boolean isRestored = false; 
     fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B); 
      if (null != fragment) { 
       // Restore fragment state from the BackStack 
       fragmentB = (FragmentB) fragment; 
       isRestored = true; 
      } 

     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction() 
                     .setCustomAnimations(R.anim.frag_fade_in, 
                           R.anim.frag_fade_out, 
                           R.anim.frag_fade_in, 
                           R.anim.frag_fade_out); 

     transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B); 
     if(!isRestored){ 
      transaction.addToBackStack(TAG_FRAG_B) 
     } 
     transaction.commit(); 
    } else { 
     // Just pop any fragments that were added - usually we won't get in here 
     getSupportFragmentManager().popBackStack(); 
    } 
} 

Это в сочетании с onBackPressed() переопределение:

@Override 
public void onBackPressed() { 
    if (isCurrentFragmentB()) { 
     toggle(); 
    } else { 
     // Back key was pressed and we are on fragment A - at this state we simply want to go back to the 
     // previous section 
     super.onBackPressed(); 
    } 
} 

Используя эту реализацию, я убедиться, что я повторно фрагмент B и сохраните его состояние, чтобы оно не выглядело так, будто оно создается с нуля каждый раз. Я также убеждаюсь, что когда я вернусь, я могу перейти только от фрагмента B к A, а не от фрагмента A к B.

Проблема, с которой я столкнулся, заключается в том, что когда вызывается super.onBackPressed(); и добавлено несколько фрагментов (заменено на самом деле, как я хочу только один активный фрагмент в то время) через менеджер фрагмента, он будет бросать исключение:

java.lang.IllegalStateException: Fragment already added: FragmentA{af9c26b #0 id=0x7f0e00d3} 

Это только происходит, когда активный фрагмент Fragmenta. У меня есть подозрение, что это из-за реализации BackStack, но, как я уже сказал, я хочу, чтобы второй сохранялся.

Как это исправить? Я что-то упустил?

ответ

0

Мне удалось реализовать обход для этого, хотя он немного взломан.

Поскольку мне нужно сохранить состояние FragmentB, я вынужден добавить его в BackStack, но это фактически повлияет на то, какой переход будет отменен при вызове onBackPressed().

Чтобы избежать этого, я должен был обновить логику для обратной печати и вручную обрабатывать этот случай

@Override 
public void onBackPressed() { 
    if (isCurrentFragmentB()) { 
     toggle(); 
    } else if (isCurrentFragmentA()) { 
     getSupportFragmentManager().popBackStackImmediate(TAG_FRAG_A, FragmentManager.POP_BACK_STACK_INCLUSIVE); 
     // Special case - because we added the fragment B to the BackStack in order to easily resume it's state, 
     // this will fail as it will actually try to add fragment A again to the fragment manager (it 
     // will try to reverse the last transaction) 
     super.finish(); 
    } else { 
     // Usual flow - let the OS decide what to do 
     super.onBackPressed(); 
    } 
} 

Кроме того, я оптимизирован метод переключить немного:

public void toggle() { 
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 

    @SuppressLint("CommitTransaction") FragmentTransaction transaction = 
       getSupportFragmentManager().beginTransaction() 
              .setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out, 
                   R.anim.frag_fade_in, R.anim.frag_fade_out); 

    if (fragment instanceof FragmentB && null != fragmentA) { 
     // fragment B is visible - we should show fragment A 

     fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_A); 
     if (null != fragment) { 
      // Restore fragment state from the BackStack 
      fragmentA = (FragmentA) fragment; 
     } 

     // Replace current fragment with fragment A and commit the transaction 
     transaction.replace(R.id.fragment_container, fragmentA, TAG_FRAG_A).commit(); 
    } else if (fragment instanceof FragmentA && null != fragmentB) { 
     // fragment A is visible - we should show fragment B 

     fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B); 
      if (null != fragment) { 
       // Restore fragment state from the BackStack 
       fragmentB = (FragmentB) fragment; 
      } 

     // Replace current fragment with fragment B 
     transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B); 

     if (null == fragment) { 
       // No entry of the fragment B in the BackStack, we want to add it for future uses 
       transaction.addToBackStack(TAG_FRAG_B); 
      } 

      // Commit the transaction 
      transaction.commit(); 
    } else { 
     // Just pop any fragments that were added - usually we won't get in here 
     getSupportFragmentManager().popBackStack(); 
    } 
} 

Надеюсь, это поможет другим, которым нужен подобный поток.

PS: фрагмент, который я хочу сохранить, - SupportMapFragment, так что моя карта не всегда перерисовывается, перецентрируется и заполняется данными каждый раз, когда я хочу ее показать.

Смежные вопросы