Урок 104. Android 3. Fragments. Lifecycle

Обсуждение уроков
avex
Сообщения: 24
Зарегистрирован: 22 дек 2013, 06:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение avex » 15 июн 2014, 11:47

Это из вашего же кода, раз вы так написали, значит вы в классе должны были задекларировать
Если бы из моего. Это из прекрасно работающего приложения, которое я хочу заставить работать во фрагменте, в паре (на одном экране) с другим фрагментом. Пока не получается.
Если просто добавить getActivity() к getPreferences, эклипс говорит об ошибке:
The constructor FirstView(Fragment2, SharedPreferences, RelativeLayout) is undefined
И в качестве исправления предлагает два варианта:
Change constructor FirstView (Context, SharedPreferences, RelativeLayout) to FirstView (Fragment2, SharedPreferences, RelativeLayout)
и Create constructor FirstView (Fragment2, SharedPreferences, RelativeLayout)

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Viewer » 15 июн 2014, 11:54

И в качестве исправления предлагает два варианта:
Ну так приходится только гадать что у вас там за конструктор. Если передается контекст, то нужно передавать контекст опять же Activity, у фрагмента нет контекста, он использует контекст Activity, т.е. вместо
"this" тоже нужно написать getActivity()

avex
Сообщения: 24
Зарегистрирован: 22 дек 2013, 06:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение avex » 15 июн 2014, 12:04

Ну так приходится только гадать что у вас там за конструктор.
Где посмотреть его тип?
т.е. вместо "this" тоже нужно написать getActivity()
Вот так?:

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

view = new SomeView(getActivity(), getActivity().getPreferences(Context.MODE_PRIVATE),
layout);

avex
Сообщения: 24
Зарегистрирован: 22 дек 2013, 06:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение avex » 15 июн 2014, 12:23

Viewer, спасибо большое!
Осталось одно - эклипс придирается к типу моего view. Как узнать тип, где это посмотреть?

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Viewer » 15 июн 2014, 13:03

avex писал(а): Осталось одно - эклипс придирается к типу моего view. Как узнать тип, где это посмотреть?
Если в программе, которую вы переписываете написано именно так, без указания типа, значит переменная view определена как поле класса, поэтому видна во всех методах класса.
Поэтому где-то в классе должно быть объявление этой переменной что-то типа
private SomeView view;

avex
Сообщения: 24
Зарегистрирован: 22 дек 2013, 06:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение avex » 15 июн 2014, 13:47

Спасибо большое, вставил в начало класса SomeView view; и теперь эклипс перестал ругаться.

avex
Сообщения: 24
Зарегистрирован: 22 дек 2013, 06:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение avex » 27 июн 2014, 08:00

Ошибки во всех файлах в эклипсе ликвидированы, но само приложение не запускается. Можно ли сюда выложить логи, как в SO, чтобы знающие посоветовали, как их исправлять?
Выложу на всякий случай. Если что, эмулятор - Genymotion, с другими приложениями все работает нормально.

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

06-27 04:49:03.715: D/AndroidRuntime(991): Shutting down VM

06-27 04:49:03.715: W/dalvikvm(991): threadid=1: thread exiting with uncaught exception (group=0xa6244288)

06-27 04:49:03.719: E/AndroidRuntime(991): FATAL EXCEPTION: main

06-27 04:49:03.719: E/AndroidRuntime(991): java.lang.RuntimeException: Unable to resume activity {com.example.frag106_3/com.example.frag106_3.MainActivity}: java.lang.NullPointerException

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.access$600(ActivityThread.java:130)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.os.Handler.dispatchMessage(Handler.java:99)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.os.Looper.loop(Looper.java:137)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.main(ActivityThread.java:4745)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at java.lang.reflect.Method.invokeNative(Native Method)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at java.lang.reflect.Method.invoke(Method.java:511)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at dalvik.system.NativeStart.main(Native Method)

06-27 04:49:03.719: E/AndroidRuntime(991): Caused by: java.lang.NullPointerException

06-27 04:49:03.719: E/AndroidRuntime(991): 	at com.example.frag106_3.Fragment2.onResume(Fragment2.java:50)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:874)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1812)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.Activity.performResume(Activity.java:5092)

06-27 04:49:03.719: E/AndroidRuntime(991): 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)

06-27 04:49:03.719: E/AndroidRuntime(991): 	... 12 more

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Mikhail_dev » 27 июн 2014, 10:34

06-27 04:49:03.719: E/AndroidRuntime(991): Caused by: java.lang.NullPointerException

06-27 04:49:03.719: E/AndroidRuntime(991): at com.example.frag106_3.Fragment2.onResume(Fragment2.java:50)

Аватара пользователя
Sergo
Сообщения: 8
Зарегистрирован: 02 авг 2014, 17:19

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Sergo » 04 авг 2014, 14:52

Доброго времени всем. вот такой вот вопросик у меня. у меня в фрагменте куча переменных, при использовании setRetainInstance(true); они вообще должны ли сохраняться, или я просто не улавливаю смысла этого метода. метод setRetainInstance(true); вызываю в onCreateView фрагмента.

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Mikhail_dev » 04 авг 2014, 15:51

Да, должен. Если проводить аналогию, то данный метод подобен
android:configChanges="orientation|keyboard|keyboardHidden"

http://www.androiddesignpatterns.com/20 ... anges.html
By default, Fragments are destroyed and recreated along with their parent Activitys when a configuration change occurs. Calling Fragment#setRetainInstance(true) allows us to bypass this destroy-and-recreate cycle, signaling the system to retain the current instance of the fragment when the activity is recreated.
Если поставить данный флаг, то в жизненном цикле при повороте не вызовется метод onCreate (не путать с методом onCreate активити)
public void setRetainInstance (boolean retain)

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
onCreate(Bundle) will not be called since the fragment is not being re-created.
onAttach(Activity) and onActivityCreated(Bundle) will still be called.

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Viewer » 05 авг 2014, 12:51

Единственное о чем нужно не забывать, что setRetainInstance(true) должен использоваться только в целях ускорения (к примеру при повороте экрана и т.п.), но полагаться на него не стоит (нет никаких гарантий, что система не уничтожит фрагмент и все его данные) нужно так же сохранять и восстанавливать все свои переменные через onSaveInstanceState в savedInstanceState.
При использовании setRetainInstance(true) лучше всего инициализировать переменные в onCreate т.к. он не будет вызываться, если переменные были сохранены (как замечено постом выше), поэтому можно не переживать, что они будут инициализироваться повторно, там же можно предусмотреть и восстановление из savedInstanceState, на случай если система уничтожит данные (if (savedInstanceState != null) {})
Еще нюанс в том, что UI будет всегда инициализироваться по-новой и метод onCreateView будет вызываться всегда (оно и понятно- при повороте изменяется конфигурация), вам нужно будет только заполнять UI сохраненными данными, а ссылки на элементы UI сохранять ни в коем случае не нужно.

Кстати довольно часто попадаются приложения, которые вроде бы нормально работают, при поворотах все корректно, но если их запустить повторно, через некоторое время, или через диспетчер задач, особенно после очистки памяти, то они падают, это говорит о неправильной обработке восстановления.


Realist
Сообщения: 134
Зарегистрирован: 08 фев 2014, 18:15

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Realist » 09 сен 2014, 07:22

Со статическими фрагментами все понятно, а вот с динамическими возникает проблема:
В активности в onCreate добавляется фрагмент

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

fragment = new Fragment1();
getSupportFragmentManager()
				.beginTransaction()
				.replace(R.id.container1,fragment1)
				.commit();
После запуска приложения lifecycle-методы вызываются в таком порядке

Activity onCreate
Fragment1 onAttach
Activity onAttachFragment
Fragment1 onCreate
Fragment1 onCreateView
Fragment1 onActivityCreated


Если нажать кнопку back и снова запустить приложение, порядок будет тот же.
Но если повернуть экран, то порядок изменится

Fragment1 onAttach
Activity onAttachFragment
Fragment1 onCreate
Activity onCreate
Fragment1 onCreateView
Fragment1 onActivityCreated


Почему onCreate активности теперь вызывается после onCreate фрагмента и что вообще происходит с активностью, когда система завершает ее в принудительном порядке, кроме вызова onSaveInstanceState?

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Mikhail_dev » 09 сен 2014, 08:30

В первом случае вы создаете фрагмент при уже созданной активности (код вы ведь вызываете в каком-то жизненном цикле активности). Во втором случае (при повороте), фрагмент пересоздается самим андроидом, и фрагмент проходит определенные жизненные циклы взависимости от того, где вы его создаете. Скажу просто: старайтесь юзать основные методы активностей и фрагментов:
- для активности это все её методы
- для фрагмента, это все, кроме onCreate, onAttach, onDetach, onDestroy

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

Realist
Сообщения: 134
Зарегистрирован: 08 фев 2014, 18:15

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Realist » 09 сен 2014, 11:37

Mikhail_dev писал(а):В первом случае вы создаете фрагмент при уже созданной активности (код вы ведь вызываете в каком-то жизненном цикле активности). Во втором случае (при повороте), фрагмент пересоздается самим андроидом, и фрагмент проходит определенные жизненные циклы взависимости от того, где вы его создаете. Скажу просто: старайтесь юзать основные методы активностей и фрагментов:
- для активности это все её методы
- для фрагмента, это все, кроме onCreate, onAttach, onDetach, onDestroy

Просто тут есть довольно труднопонимаемые тонкости, которыми пока что не засоряйте голову.
Тогда подскажите пожалуйста, как быть. Мне нужно из активности поставить SimpleAdapter на ListView фрагмента.
В OnCreate активности пишу:

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

fragment1 = new Fragment1(); 
getSupportFragmentManager() 
                .beginTransaction() 
                .replace(R.id.container1,fragment1) 
                .commit();


Если сделать это сразу после вызова метода commit(), то код
(ListView) fragment1.getView().findViewById(R.id.fragmentListView).setAdapter(adapter)
выдаст ошибку NullPointerException , так как fragment1.isAdded() тут будет еще false.
Я делаю так - вешаю на активность интерфейс, объект которого передаю фрагменту в OnAttach и уже оттуда в методе onActivityCreated вызываю метод интерфейса в активности, в котором и ставлю адаптер и в котором fragment1.isAdded() уже true.
И если просто запускать приложение, то все работает. А вот при повороте экрана в этом методе fragment1.isAdded() по прежнему false и приложение падает с ошибкой. :)
Вообще в активности по идее должен быть метод типа onFragmentAdded, который бы вызывался, когда фрагмент добавлен и можно начинать обращаться к его виджетам, но я такого метода не нашел=)
В общем, посоветуйте что-нибудь=)

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Mikhail_dev » 09 сен 2014, 11:54

Тогда подскажите пожалуйста, как быть. Мне нужно из активности поставить SimpleAdapter на ListView фрагмента.
Вообще то это должен делать фрагмент, а не активность. Фрагмент является списком, пусть он и создает адаптер.
Если сделать это сразу после вызова метода commit(), то код
(ListView) fragment1.getView().findViewById(R.id.fragmentListView).setAdapter(adapter)
выдаст ошибку NullPointerException , так как fragment1.isAdded() тут будет еще false.
да, потому что создание фрагмента происходит асихронно и сразу же после коммита, он не создастся. Ему нужно время.
Я делаю так - вешаю на активность интерфейс, объект которого передаю фрагменту в OnAttach и уже оттуда в методе onActivityCreated вызываю метод интерфейса в активности, в котором и ставлю адаптер и в котором fragment1.isAdded() уже true.
и это совершенно правильно.
Вообще в активности по идее должен быть метод типа onFragmentAdded, который бы вызывался, когда фрагмент добавлен и можно начинать обращаться к его виджетам, но я такого метода не нашел=)
Его нет. Я тоже мучался с этим. Решал проблему разными способами
1. Через слушатель, где я получаю данные в onActivityCreated. Т.е. фрагмент спрашивает данные когда создастся, а не активность их отдает. Тогда фрагмент железно будет создан.
2. Фрагмент отсылает бродкаст о том, что он создан (бросаю его в методе onActivityCreated, либо onStart или onResume), после чего активность заполняет фрагмент.
3. Фрагмент берет данные с кеша (либо базы, и т.д.), которые не лежат в активности.

Realist
Сообщения: 134
Зарегистрирован: 08 фев 2014, 18:15

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Realist » 09 сен 2014, 13:32

Mikhail_dev писал(а): Вообще то это должен делать фрагмент, а не активность. Фрагмент является списком, пусть он и создает адаптер.
Просто хотелось максимально отгородить фрагменты от выполнения каких то операций. Повесить слушатели и все. Все-таки контроллер это Activity..
Mikhail_dev писал(а): Его нет. Я тоже мучался с этим. Решал проблему разными способами
1. Через слушатель, где я получаю данные в onActivityCreated. Т.е. фрагмент спрашивает данные когда создастся, а не активность их отдает. Тогда фрагмент железно будет создан.
2. Фрагмент отсылает бродкаст о том, что он создан (бросаю его в методе onActivityCreated, либо onStart или onResume), после чего активность заполняет фрагмент.
3. Фрагмент берет данные с кеша (либо базы, и т.д.), которые не лежат в активности.
Спасибо, попробую сначала 2-е через onStart или onResume. Через onActivityCreated, как оказалось, не катит..

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Mikhail_dev » 09 сен 2014, 14:48

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

Realist
Сообщения: 134
Зарегистрирован: 08 фев 2014, 18:15

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Realist » 20 сен 2014, 20:12

В общем решил проблему гораздо элегантнее - поставил таймер на 1 секунду, за это время фрагмент гарантированно ставится :D И фрагменты наполнил чуток, так действительно легче.

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

Re: Урок 104. Android 3. Fragments. Lifecycle

Сообщение Foenix » 20 сен 2014, 20:14

Realist писал(а):В общем решил проблему гораздо элегантнее - поставил таймер на 1 секунду, за это время фрагмент гарантированно ставится :D И фрагменты наполнил чуток, так действительно легче.
ну элегантным решение не назовешь. Присутствие таймера в программе - плохой код. Лучше изучить их жизненный цикл получше и сделать что хочешь.
R.id.team

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

Ответить