Это уменьшенная версия фактической проблемы. Чтобы воссоздать трудность, с которой я столкнулся.Портрет макета не работает, когда активность начинается в ландшафте
Я привел пример с официального сайта developer.android.com
, чтобы привести мою проблему. Building a Flexible UI
MainActivity
имеет 2 макета. Один для макета по умолчанию (портрет в малогабаритных устройствах) в папке layout
. Другая компоновка как для режима большого экрана, так и для ландшафта, содержалась в папке layout-large
и layout-land
.
Стандарт по умолчанию для activity_main.xml
содержит только один FrameLayout
(R.id.fragment_container
), в котором я добавляю и заменяю 2 фрагмента, которые я создаю, динамически.
Другие макеты одинаковы для каталогов layout-land
и layout-large
. Он имеет 2 статических фрагмента [R.id.headlines_fragment
- для отображения списка заголовков] и [R.id.article_fragment
- для отображения деталей при выборе заголовков]. По горизонтали. Один слева показывает списки, а справа - показывать детали.
Это код MainActivity.java
, который контролирует все фрагменты:
public class MainActivity extends Activity implements OnHeadLineSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_article);
if(findViewById(R.id.fragment_container) != null) {
if(savedInstanceState != null) {
return;
}
HeadlinesFragment firstFragment = new HeadlinesFragment();
firstFragment.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).commit();
}
}
@Override
public void onArticleSelected(int position) {
ArticleFragment articleFrag = (ArticleFragment) getFragmentManager().findFragmentById(R.id.article_fragment);
if(articleFrag != null && articleFrag.isVisible()) {
articleFrag.updateArticleView(position);
} else {
articleFrag = new ArticleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction().replace(R.id.fragment_container, articleFrag);
transaction.addToBackStack(null);
transaction.commit();
}
}
}
Как только начинается деятельность, я проверяю, если fragment_container
то есть FrameLayout
присутствует или нет. Если его нет, тогда будет загружен макет с 2 фрагментами. Поэтому нет необходимости добавлять динамические фрагменты, поскольку они уже присутствуют.
В противном случае, я проверяю, является ли savedInstanceState
нулевым или нет. Если null, то я создаю новый HeadlinesFragment
и добавлю его в фрейм. Если он не является нулевым, это означает, что активность уже была создана ранее, и, следовательно, должно быть добавлено значение HeadlinesFragment
. Не нужно добавлять его снова. Итак, return
.
И onArticleSelected()
метод заменяет существующий фрагмент в кадре ArticleFragment
, или если в другом макете он просто обновляет фрагмент, как он уже присутствует. Он вызывается из HeadlinesFragment
, когда элемент выбран.
Теперь все это прекрасно работает, если мы вводим операцию в портретном режиме, а затем меняем ориентацию. Нет проблем. Безупречный.
Но если мы введем действие в режиме landscape
, как только я изменю ориентацию в портретном режиме, появится пустой экран.
Причина в том, что вызывается onCreate()
, а savedInstanceState
возвращается как не null
. Следовательно, HeadlinesFragment
не создается и не добавляется к кадру.
И да, если я удалю эту проверку, приложение будет работать нормально, но это будет означать, что новый HeadlinesFragment
создается и добавляется к кадру каждый раз и укладывается поверх каждого другого. Это совсем не желательно.
Я не могу реализовать это, просто узнав orientation
и применив соответствующий макет. Поскольку в устройствах с большим экраном, даже если он находится в портретном режиме, он должен показывать оба фрагмента одновременно.
Я пробовал много запутанной логики. Но ничего не работает. Любая помощь приветствуется.
Начало деятельности в портретном режиме
1> элементы списка отображаются.
2> Нажатие на элементы заменяет фрагмент на ItemFragment (подробности).
3> Изменение ориентации, показано как бок о бок. Все работает.
Начало деятельности в ландшафтном режиме
1> Оба списка и детали показаны. Все работает.
2> Но как только ориентация изменится, вы получите пустой экран. Поскольку фрагмент заголовков не создается и не добавляется.
Было бы очень полезно, если бы кто-то может вести меня о том, как я могу решить эту проблему. И поскольку фактический проект огромен, и эта логика уже реализована, радикальное изменение в логике больше не является вариантом, так как это будет означать перебор тысяч строк кода. Спасибо. :)
Вы можете использовать .replace mtehod вместо .add, чтобы избежать укладки фрагментов друг на друга. Это не решит тот факт, что каждый раз создается новый фрагмент, хотя – GSala
Конечно, я подумал об этом, но как насчет того, что в первый раз создается ваша деятельность? в рамке ничего не заменить. Я попробовал. Это исключает. Итак, не вариант. :( –
Действительно ли это исключение? Я редко использую метод add, потому что он более удобен, и у меня не было этой проблемы. Какое исключение вы получаете? – GSala