FragmentOne fragmentOne;
FragmentTwo fragmentTwo;
public void showFragmentOne() {
if(fragmentOne == null){
fragmentOne = FragmentOne();
}
// ...
}
public void showFragmentTwo(String name) {
if(fragmentTwo == null) {
fragmentTwo = new FragmentTwo();
}
// ...
Это будет прерываться после состояния нехватки памяти , когда Android воссоздает ваши экземпляры Fragment, используя их конструктор без аргументов, вместо использования создаваемых вами здесь экземпляров. .
Хотя технически в этом конкретном случае вы используете fragmentManager.beginTransaction().replace().commit()
, следовательно, ваш экземпляр победит, а тот, который воссоздан системой, будет переопределен. Поскольку вы использовали replace
вместо add
, вы также не получите «несколько перекрывающихся фрагментов».
Однако вы потеряете способность восстановить фрагмент с помощью Fragment.onSaveInstanceState
/ Fragment.onCreate(Bundle)
, так как вы будете перезаписывать воссозданный системой фрагмент, используя свой собственный неинициализированный фрагмент.
По сути, этот подход приводит к потере состояния.
Из коробки, предполагаемое решениеэто использовать
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new FragmentOne(), "one").commit();
}
}
public void showFragmentTwo(String name) {
FragmentTwo fragmentTwo = new FragmentTwo();
Bundle bundle = new Bundle();
bundle.putString("name", name);
fragmentTwo.setArguments(bundle);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentTwo, "two")
.addToBackStack(null)
.commit();
}
}
И вы можете найти фрагменты, используя findFragmentByTag
.
Хотя мне лично не нравится обратный стек фрагментов, я считаю, что это гораздо проще, есливы отслеживаете идентификаторы, которые описывают фрагменты, которые у вас должны быть, эти идентификаторы могут предоставить вам данный тег, и вы можете установить фрагменты в любое желаемое состояние, не обязательно удаляя фрагмент (и, следовательно, теряя его представление + состояние), простопотому что вы двинулись вперед.
Вы можете проверить подход, который я склонен использовать для фрагментов здесь .
Используя следующий код, я мог установить любой Фрагмент в любое нужное состояние, не полагаясь на addToBackStack
.
public class FragmentStateChanger {
private FragmentManager fragmentManager;
private int containerId;
public FragmentStateChanger(FragmentManager fragmentManager, int containerId) {
this.fragmentManager = fragmentManager;
this.containerId = containerId;
}
public void handleStateChange(StateChange stateChange) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.disallowAddToBackStack();
// here you could animate based on direction
List<Key> previousKeys = stateChange.getPreviousKeys();
List<Key> newKeys = stateChange.getNewKeys();
for(Key oldKey : previousKeys) {
Fragment fragment = fragmentManager.findFragmentByTag(oldKey.getFragmentTag());
if(fragment != null) {
if(!newState.contains(oldKey)) {
fragmentTransaction.remove(fragment);
} else if(!fragment.isDetached()) {
fragmentTransaction.detach(fragment);
}
}
}
for(Key newKey : newKeys) {
Fragment fragment = fragmentManager.findFragmentByTag(newKey.getFragmentTag());
if(newKey.equals(stateChange.topNewKey())) {
if(fragment != null) {
if(fragment.isRemoving()) {
fragment = newKey.createFragment();
fragmentTransaction.replace(containerId, fragment, newKey.getFragmentTag());
} else if(fragment.isDetached()) {
fragmentTransaction.attach(fragment);
}
} else {
fragment = newKey.createFragment();
fragmentTransaction.add(containerId, fragment, newKey.getFragmentTag());
}
} else {
if(fragment != null && !fragment.isDetached()) {
fragmentTransaction.detach(fragment);
}
}
}
fragmentTransaction.commitAllowingStateLoss();
}
}
И затем яможет использовать это как this :
public class MainActivity
extends AppCompatActivity
implements StateChanger {
private static final String TAG = "MainActivity";
@BindView(R.id.fragment)
ViewGroup root;
FragmentStateChanger fragmentStateChanger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
fragmentStateChanger = new FragmentStateChanger(getSupportFragmentManager(), R.id.fragment);
Navigator.configure()
.setStateChanger(this)
.install(this, root, History.single(FragmentOneKey.create()));
}
@Override
public void onBackPressed() {
if(!Navigator.onBackPressed(this)) {
super.onBackPressed();
}
}
public void showSecondFragment(String data) {
Navigator.getBackstack(this).goTo(FragmentTwoKey.create(data));
}
// this handles navigation from any nav state to any other nav state
@Override
public void handleStateChange(@NonNull StateChange stateChange, @NonNull Callback completionCallback) {
if(stateChange.isTopNewKeyEqualToPrevious()) {
completionCallback.stateChangeComplete();
return;
}
fragmentStateChanger.handleStateChange(stateChange);
completionCallback.stateChangeComplete();
}
}
Не могу больше представлять фрагменты без удобства произносить backstack.goTo(SomeScreen())
вместо жонглирования транзакциями.