Отображение фрагментов при смене ориентации

Интерфейс, диалоги, темы, стили, меню
Ответить
Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Отображение фрагментов при смене ориентации

Сообщение Zammm » 29 июл 2015, 14:58

Добрый день, господа программисты!

Столкнулся с проблемкой при создании приложения, использующего фрагменты.
Загружаю в основном активити фрагменты таким образом, что последующий фрагмент замещает его предшественника. Всё бы ничего, но заметил такой баг - при смене ориентации (лайоут файлы размещения объектов при разных ориентация отличаются) на последующие фрагменты накладываются предыдущие... С чем это может быть связано и как от этого избавиться?

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: Отображение фрагментов при смене ориентации

Сообщение Mikhail_dev » 29 июл 2015, 23:13

покажите как вы добавляете/заменяете фрагменты

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 30 июл 2015, 07:28

Mikhail_dev,

в MainActivity в методе OnCreate следующее:

Код: Выделить всё

Fragment frag1 = new Primary();
	     FragmentTransaction ft = getFragmentManager().beginTransaction();
	     ft.add(R.id.frag_field, frag1);
	     ft.commit();
Т.е. при создании activity изначально загружается fragment Primary.

Далее из фрагмента Primary вызывается с заменой один из двух фрагментов следующим образом:
Во фрагменте Primary:

Код: Выделить всё

@Override
	public void onClick(View v) {

	    switch (v.getId()) {
	    case R.id.btn_info:
	    	someEventListener.someEvent("Info");
	      break;
	    case R.id.btn_list:
	    	someEventListener.someEvent("List");
	      break;
	    }
	    return;
		
	}
Код в MainActivity. Заменяем в зависимости от значения фрагмент Primary на фрагменты Info либо List:

Код: Выделить всё

public void someEvent(String s) {
		if (s == "Info") {
			Fragment frag1 = new Info();
			FragmentTransaction ft = getFragmentManager().beginTransaction();
			ft.replace(R.id.frag_field, frag1);
			ft.commit();
		}
		if (s == "List") {
			Fragment frag1 = new List();
			FragmentTransaction ft = getFragmentManager().beginTransaction();
			ft.replace(R.id.frag_field, frag1);
			ft.commit();
		}
	  }
Вот как-то так... При всём при этом фрагмент Primary при повороте экрана раз за разом загружается вновь.

Dark67
Сообщения: 72
Зарегистрирован: 23 июл 2012, 23:11

Re: Отображение фрагментов при смене ориентации

Сообщение Dark67 » 30 июл 2015, 09:09

onClick() у тебя вообще не отрабатывает, как должен. Потому что
"Info".equals(s)
"List".equals(s)

В onCreate() нужно не просто добавлять фрагмент, а сначала проверить существование фрагмента и создавать его, если его нет. Иначе, при каждом повороте экрана создается новый экземпляр фрагмента и добавляется к активности.

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 30 июл 2015, 21:01

Dark67,

Что-то моего уровня знаний не хватает, на самом деле, чтобы понять, что делать с "Info".equals(s) и "List".equals(s) чтобы всё работало корректно (где это и что это). Подскажите пожалуйста...

И, если не трудно, наведите на мысль, как реализовать сравнение в OnCreate() фрагментов... Метод или хотябы литературу на эту тему... Спасибо за помощь.

Dark67
Сообщения: 72
Зарегистрирован: 23 июл 2012, 23:11

Re: Отображение фрагментов при смене ориентации

Сообщение Dark67 » 30 июл 2015, 21:40

Сравнение строк выполняется с помощью метода equals(). То есть нужно писать не
s == "Info" , а
"Info".equals(s) (здесь впереди находится строка "Info" для того, чтобы избежать исключения NullPointerException в случае если (s == null) ).

А по поводу присоединения фрагмента к активности
[syntax=java]
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = new YourFragment();
fm.beginTransaction().add(R.id.fragment_container, fragment).commit();
}[/syntax]

Если же используется фрагмент из библиотеки поддержки (support library), то нужно вызывать метод getSupportFragmentManager().

Этот код перед тем как добавить фрагмент в контейнер, сначала проверит существует ли в системе нужный фрагмент.

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 30 июл 2015, 22:09

Dark67,
Спасибо большое за толковое объяснение. Всё понял!

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 08 авг 2015, 19:38

Верну немного тему к жизни...

В своё время мне очень помогли ваши советы, в том числе и с проверкой, создан ли фрагмент в активити при запуске... Сейчас же столкнулся с проблемой посерьёзнее - что если фрагменты в горизонтальном положении и в вертикальном - разные (различные компоновки)? На сегодняшний день, при повороте экрана у меня вылетает ошибка FATAL ERROR в MainActivity с проверкой, представленной в этой теме.

Dark67
Сообщения: 72
Зарегистрирован: 23 июл 2012, 23:11

Re: Отображение фрагментов при смене ориентации

Сообщение Dark67 » 08 авг 2015, 23:32

Полное описание ошибки в студию!

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: Отображение фрагментов при смене ориентации

Сообщение Mikhail_dev » 09 авг 2015, 00:12

Сейчас же столкнулся с проблемой посерьёзнее - что если фрагменты в горизонтальном положении и в вертикальном - разные (различные компоновки)?
А ничего. Создайте в обоих XML файлах контейнеры с одинаковым id, куда будете добавлять фрагмент. Падает наверное потому что у вас id (fragment_container) не во всех XML файлах есть?
И еще, используйте .replace для добавления фрагмента, а не .add

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 09 авг 2015, 11:41

Посмотрел, контейнеры и существуют и совпадают по id как в вертикальной компоновке, так и в land. Поменял add на replace - та же фигня... При том использую replace и до этого использовал при замещении фрагментов в дальнейшем. Самое что интересное - проблема существует только с первым, заглавным фрагментом, который я и вставляю при проверке. Последующие фрагменты при смене ориентации ведут себя нормально.

Лог ошибки:
08-09 11:35:09.259: E/AndroidRuntime(14781): FATAL EXCEPTION: main
08-09 11:35:09.259: E/AndroidRuntime(14781): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.friends_home/com.example.memodtp.MainActivity}: java.lang.NullPointerException
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2121)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2146)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3590)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.access$800(ActivityThread.java:140)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.os.Handler.dispatchMessage(Handler.java:99)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.os.Looper.loop(Looper.java:137)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.main(ActivityThread.java:4944)
08-09 11:35:09.259: E/AndroidRuntime(14781): at java.lang.reflect.Method.invokeNative(Native Method)
08-09 11:35:09.259: E/AndroidRuntime(14781): at java.lang.reflect.Method.invoke(Method.java:511)
08-09 11:35:09.259: E/AndroidRuntime(14781): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
08-09 11:35:09.259: E/AndroidRuntime(14781): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
08-09 11:35:09.259: E/AndroidRuntime(14781): at dalvik.system.NativeStart.main(Native Method)
08-09 11:35:09.259: E/AndroidRuntime(14781): Caused by: java.lang.NullPointerException
08-09 11:35:09.259: E/AndroidRuntime(14781): at com.example.memodtp.Primary.onCreateView(Primary.java:43)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:829)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1806)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.Activity.performCreate(Activity.java:5191)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
08-09 11:35:09.259: E/AndroidRuntime(14781): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2085)
08-09 11:35:09.259: E/AndroidRuntime(14781): ... 12 more

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Отображение фрагментов при смене ориентации

Сообщение Foenix » 09 авг 2015, 13:58

по ссылке в подписи
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Dark67
Сообщения: 72
Зарегистрирован: 23 июл 2012, 23:11

Re: Отображение фрагментов при смене ориентации

Сообщение Dark67 » 09 авг 2015, 22:28

Чтобы фрагмент пережил смену ориентации, в его код добавляют setRetainInstance(true)

метод replace() нужен для смены одного фрагмента другим. Тебе же надо восстанавливать состояние существующего фрагмента.

А вообще, почитай про жизненные циклы фрагментов и активити.

Кстати, у тебя фрагмент прописан в XML? (Всмысле, в коде разметки активити)

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 10 авг 2015, 23:32

контейнер для вставки фрагмента в xml activity прописан...
Спасибо большое за информацию, почитаю углублённее о жизненных циклах фрагментов... и попробую использовать предложенное)

Аватара пользователя
Sk_games
Сообщения: 77
Зарегистрирован: 20 янв 2014, 21:13

Re: Отображение фрагментов при смене ориентации

Сообщение Sk_games » 11 авг 2015, 14:56

Zammm
И еще, используйте .replace для добавления фрагмента, а не .add
Вот тебе человек написал. поправь это изменение, и снимет все, как рукой. (Если проблемой остается налаживание фрагментов один на один)

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: Отображение фрагментов при смене ориентации

Сообщение Mikhail_dev » 11 авг 2015, 14:59

не снимет. я просто указал на то, как лучше делать, а ошибка у него в другом. foenix ему верно написала.

Zammm
Сообщения: 69
Зарегистрирован: 05 окт 2014, 11:31

Re: Отображение фрагментов при смене ориентации

Сообщение Zammm » 11 авг 2015, 19:24

Большущее спасибо всем за потраченное на вразумление время! Вы мне очень помогли - ошибка NPE по foenix была в методе OnCreate в коде заглавного фрагмента:
Одна из объявленных buttton не совпадала по id с существующей button в xml фрагмента для land. После устранения этой нелепой оплошности всё заработало как часы!

Получилось как со студентом, который может, но недостаточно усердно занимается. Ошибся, а после недостаточно приложил усилий для реабилитации.

Ответить