Страница 5 из 6

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

Добавлено: 15 июн 2014, 11:47
avex
Это из вашего же кода, раз вы так написали, значит вы в классе должны были задекларировать
Если бы из моего. Это из прекрасно работающего приложения, которое я хочу заставить работать во фрагменте, в паре (на одном экране) с другим фрагментом. Пока не получается.
Если просто добавить 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)

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

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

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

Добавлено: 15 июн 2014, 12:04
avex
Ну так приходится только гадать что у вас там за конструктор.
Где посмотреть его тип?
т.е. вместо "this" тоже нужно написать getActivity()
Вот так?:

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

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

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

Добавлено: 15 июн 2014, 12:23
avex
Viewer, спасибо большое!
Осталось одно - эклипс придирается к типу моего view. Как узнать тип, где это посмотреть?

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

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

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

Добавлено: 15 июн 2014, 13:47
avex
Спасибо большое, вставил в начало класса SomeView view; и теперь эклипс перестал ругаться.

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

Добавлено: 27 июн 2014, 08:00
avex
Ошибки во всех файлах в эклипсе ликвидированы, но само приложение не запускается. Можно ли сюда выложить логи, как в 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

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

Добавлено: 27 июн 2014, 10:34
Mikhail_dev
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)

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

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

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

Добавлено: 04 авг 2014, 15:51
Mikhail_dev
Да, должен. Если проводить аналогию, то данный метод подобен
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.

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

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

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

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

Добавлено: 05 авг 2014, 13:41
Mikhail_dev
Очень верные уточнения

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

Добавлено: 09 сен 2014, 07:22
Realist
Со статическими фрагментами все понятно, а вот с динамическими возникает проблема:
В активности в 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?

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

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

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

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

Добавлено: 09 сен 2014, 11:37
Realist
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, который бы вызывался, когда фрагмент добавлен и можно начинать обращаться к его виджетам, но я такого метода не нашел=)
В общем, посоветуйте что-нибудь=)

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

Добавлено: 09 сен 2014, 11:54
Mikhail_dev
Тогда подскажите пожалуйста, как быть. Мне нужно из активности поставить 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. Фрагмент берет данные с кеша (либо базы, и т.д.), которые не лежат в активности.

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

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

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

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

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

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

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

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