1

Это уменьшенная версия фактической проблемы. Чтобы воссоздать трудность, с которой я столкнулся.Портрет макета не работает, когда активность начинается в ландшафте

Я привел пример с официального сайта 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> Изменение ориентации, показано как бок о бок. Все работает.

HeadlinesFragment is shown. --->ArticleFragment is shown on clicking a list item

Both shown in the landscape mode

Начало деятельности в ландшафтном режиме

1> Оба списка и детали показаны. Все работает.

2> Но как только ориентация изменится, вы получите пустой экран. Поскольку фрагмент заголовков не создается и не добавляется.

Entering Activity in landscape mode ->HeadlinesFragment not shown. Nothing loads. Blank Screen.

Было бы очень полезно, если бы кто-то может вести меня о том, как я могу решить эту проблему. И поскольку фактический проект огромен, и эта логика уже реализована, радикальное изменение в логике больше не является вариантом, так как это будет означать перебор тысяч строк кода. Спасибо. :)

+0

Вы можете использовать .replace mtehod вместо .add, чтобы избежать укладки фрагментов друг на друга. Это не решит тот факт, что каждый раз создается новый фрагмент, хотя – GSala

+0

Конечно, я подумал об этом, но как насчет того, что в первый раз создается ваша деятельность? в рамке ничего не заменить. Я попробовал. Это исключает. Итак, не вариант. :( –

+0

Действительно ли это исключение? Я редко использую метод add, потому что он более удобен, и у меня не было этой проблемы. Какое исключение вы получаете? – GSala

ответ

0

Загрузите образец кода с этого сайта разработчика и внесите изменения в соответствии с вашими потребностями.

Build Dynamic UI with fragments

Его супер и надежный код.

+0

Если вы заметите, это точно мой код. Это точная проблема, которую я скопировал здесь. Это хорошо работает для больших экранов и устройств с маленькими экранами, но не сменяет ориентацию. –

+0

oh! Позвольте мне проверить код. как можно быстрее. –

0

Я уверен, что есть причины, по которым Fragment было вынесено правильно Portrait -> Landscape, а не в обратном направлении, но одна вещь очень четкое представление о жизненном цикле Activity

Called когда активность начинает. Это где большинство инициализации должна идти: вызов setContentView(int) раздувать UI в активности, используя findViewById(int) программно взаимодействовать с виджетами в пользовательском интерфейсе, вызывая managedQuery(android.net.Uri, String[], String, String[], String) для извлечения курсоров для данных отображается и т.д.

Примечания часть, которая говорит Здесь большинство инициализации должно идти. Выйдя после проверки того, что savedInstanceState имеет значение null, вы оставляете его до класса super, чтобы восстановить Fragment, что не является хорошей идеей, учитывая, что предыдущее представление было уничтожено.

Мой совет, ознакомьтесь с содержанием savedInstanceState, а не просто проверяйте, является ли оно нулевым. Убедитесь, что он содержит достаточно данных для восстановления вашего предыдущего состояния, если не инициализировать ваш фрагмент.

Рекомендации по использованию фрагментов включают в себя реализацию всех необходимых методов контроля состояния.

+0

Это не проблема, потому что, как только я вхожу в портретный режим, изменение ориентации несколько раз не влияет на фрагменты. У savedInstanceState есть соответствующая информация. Проблема возникает при создании активности из ландшафтного режима. Пакет не является нулевым, но информации о фрагменте нет. Потому что он не был создан. Я знаю это. Я знаю точную проблему. Да, файл saveInstanceState в этом случае не имеет фрагмента. Я знаю это. но я не могу найти способ исправить это, не мешая остальной части кода. Я много пробовал. :( –

+0

@SamratDutta если возможно, могу ли я получить доступ к полному источнику, чтобы я мог его запустить и проверить? – Olayinka

1

Хорошо. У меня проблема. Проблема в том, что мы используем Fragments в xml-макетах на больших устройствах.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <fragment android:name="com.example.android.fragments.HeadlinesFragment" 
       android:id="@+id/headlines_fragment" 
       android:layout_weight="1" 
       android:layout_width="0dp" 
       android:layout_height="match_parent" /> 

    <fragment android:name="com.example.android.fragments.ArticleFragment" 
       android:id="@+id/article_fragment" 
       android:layout_weight="2" 
       android:layout_width="0dp" 
       android:layout_height="match_parent" /> 

</LinearLayout> 

Так андроид пытается поймать фрагменты в savedInstanceState в MainActivity. Когда экран вращается, система пытается восстановить вышеописанные фрагменты, даже если разные макеты загружаются в режиме пота. И поэтому система считает, что article_fragment также доступен с правой стороны, и он пытается обновить его при нажатии на Заголовок.

Итак, что такое решение?

Я изменил немного кода в MainActivity и ничего больше :-)

/** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(null); 
     setContentView(R.layout.news_articles); 

     // Check whether the activity is using the layout version with 
     // the fragment_container FrameLayout. If so, we must add the first fragment 
     if (findViewById(R.id.fragment_container) != null) { 

      // However, if we're being restored from a previous state, 
      // then we don't need to do anything and should return or else 
      // we could end up with overlapping fragments. 
      /*if (savedInstanceState != null) { 
       return; 
      }*/ 

      // Create an instance of ExampleFragment 
      HeadlinesFragment firstFragment = new HeadlinesFragment(); 

      // In case this activity was started with special instructions from an Intent, 
      // pass the Intent's extras to the fragment as arguments 
      firstFragment.setArguments(getIntent().getExtras()); 

      // Add the fragment to the 'fragment_container' FrameLayout 
      getSupportFragmentManager().beginTransaction() 
        .add(R.id.fragment_container, firstFragment).commit(); 
     } 
    } 

Так что я сделал только я сказал, что систему я не хочу каких-либо вещь, восстановленное с помощью super.onCreate(null); поэтому его ничего не восстанавливая.

О пустом экране вы получаете

Всякий раз, когда вы начинаете деятельность в ландшафтном режиме. По умолчанию он загружает большой дисплей. Без ввода если заявка. Потому что он не может получить fragment_container в ландшафтном режиме. И затем вы поворачиваете экран, чтобы загрузить портретный макет, и система получает savedInstanceState != null и возвращается без загрузки HeadlinesFragment. Таким образом, вы получаете банковский экран.

Так что я прокомментировал это заявление, как вы можете заметить.

/*if (savedInstanceState != null) { 
        return; 
    }*/ 

Итак, теперь он загружает все правильно. No issue

+0

Похоже на возможное решение. Я проверю его сегодня. Если это сработает, я вернусь и приму этот ответ. В любом случае, спасибо за ваше время и усилия. :) Очень ценю. –

+0

Не волнуйся. Я уже проверил это. В любом случае я разработчик не хороший тестер ... –

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

  • Нет связанных вопросов^_^