2014-11-01 4 views
22

я в настоящее время создания приложения для Android (14 < = SDK < = 21), используя один ActionBarActivity и более Fragments, такие как ListFragment и MapFragment, которые выгружены в рамках одного FrameLayout вид.Фрагмент addToBackStack() и popBackStackImmediate() не работает

ActionBarActivity автоматически заменяет/фиксирует фрагмент A. Затем, когда пользователь нажимает кнопку, хостинговая деятельность заменяет/фиксирует новый другой фрагмент B. Моя цель - позволить пользователю вернуться к фрагменту A, как только она нажимает кнопку «Назад».

Некоторый код сейчас.

MainActivity

public class MainActivity extends ActionBarActivity implements StopFragment.OnFragmentInteractionListener, 
    StopItemFragment.OnFragmentInteractionListener { 
... 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     fragmentManager = getFragmentManager(); 
     fragmentManager.enableDebugLogging(true); 
     ... 
     if (fragmentManager.findFragmentById(R.id.content_frame) == null) { 
      StopItemFragment list = StopItemFragment.newInstance(null); //A - extends ListFragment 
      fragmentManager.beginTransaction() 
       .replace(R.id.content_frame, list) 
       .addToBackStack(null) 
       .commit(); 
     } 
     ... 

     @Override 
     public void onFragmentInteraction(String id) { 
     selectItem(Integer.parseInt(id)); 
     } 


     private void selectItem(int position) { 
     StopFragment fragment = StopFragment.newInstance(null, null); //B - extends Fragment 
     ... 
     fragmentManager.beginTransaction() 
      .replace(R.id.content_frame, fragment) 
      .commit(); 

     ... 
     } 
} 


Проблема

Даже если addToBackStack() называется, когда я на фрагменте B, я не могу вернуться к фрагменту А. MainActivity непосредственно закрыт. Тем не менее я старался самостоятельно управлять задним стеклом. Я вижу, что фрагмент находится в стеке, но если я вызываю popBackStackImmediate(), фрагмент A выскочит и транзакция фрагмента не будет выполнена. (Первый назад пресса ничего не произойдет, вторая активность закрыта)

Я придаю также FragmentManager LogCat:
http://pastebin.com/hFLHprL8

ответ

64

Для тех, кто все еще ищет решения.

В основном Activity класс (который размещает фрагменты) просто переопределяет onBackPressed().

@Override 
public void onBackPressed() { 
    if (getFragmentManager().getBackStackEntryCount() > 0){ 
     getFragmentManager().popBackStack(); 
    } else { 
     super.onBackPressed(); 
    } 
} 

Там нет onBackPressed() метод фрагмента, и этот метод только для activity. Таким образом, когда мы нажимаем клавишу возврата, поведение по умолчанию activity показано, что

вы либо перейти к предыдущей деятельности (если таковая имеется) или приложение выйдет.

Теперь нам нужно переопределить этот метод, чтобы сказать activity, что, когда мы нажимаем клавишу возврата, если есть какие-либо фрагменты в задней стеке, совать их (и это когда addToBackStack() входит в картину). В противном случае выполните поведение по умолчанию.

+2

Спасибо. Интересно, почему в документации по Android нет упоминания об этой важной вещи? Или я просто пропустил это ... – Ryde

5

Попробуйте это (Примечание добавить не заменить для Fragmenta и addToBackStack() для fragmentB)

StopItemFragment list = StopItemFragment.newInstance(null); //A - extends ListFragment 
     fragmentManager.beginTransaction() 
      .add(R.id.content_frame, list) 
      .commit(); 

и

StopFragment fragment = StopFragment.newInstance(null, null); //B - extends Fragment 
    ... 
    fragmentManager.beginTransaction() 
     .replace(R.id.content_frame, fragment) 
     .addToBackStack("FragmentB") 
     .commit(); 
+1

Таким образом я добавляемого на фрагмент стека B, но не А. Из 'FragmentTransaction' документации: ' addToBackStack(): Добавить эту операцию на спине стека. Это означает, что транзакция будет запомнена после того, как она будет совершена, и изменит ее работу, когда позже выскочит со стека. « – Emanuele

4

Мне пришлось позвонить beginTransaction() и commit() из FragmentManager вручную.
решаемые перекрывая onBackPressed():

@Override 
public void onBackPressed() { 
    ... 
    if (fragmentManager.getBackStackEntryCount() > 1){ 
     fragmentManager.popBackStackImmediate(); 
     fragmentManager.beginTransaction().commit(); 
    } else { 
     //handle finish 
     finish(); // Closes app 
    } 
} 
1

Если вы боретесь с addToBackStack() & popBackStack(), а затем просто использовать

FragmentTransaction ft =getSupportFragmentManager().beginTransaction(); 
ft.replace(R.id.content_frame, new HomeFragment(), "Home"); 
ft.commit();` 

В вашей деятельности в OnBackPressed() узнать fargment по тэгу, а затем сделать ваши вещи

Fragment home = getSupportFragmentManager().findFragmentByTag("Home"); 

if (home instanceof HomeFragment && home.isVisible()) { 
    // do you stuff 
} 

Для получения дополнительной информации https://github.com/DattaHujare/NavigationDrawer Я никогда не использую addToBackStack() для обработки фрагмента.

0

Причина, по которой и popBackStackImmediatly() связаны с тем, что вы не добавили этот фрагмент (который вы хотите поп) на backStack. Для этого вам нужно сделать вызов addToBackStack() в момент, когда транзакция добавит/заменит ваш фрагмент.

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