Объекты связи между несколькими фрагментами в ViewPager
У меня есть 5 фрагментов в ViewPager
, используемых для заполнения бизнес-объекта несколькими полями шаг за шагом, на каждом шаге будут установлены некоторые из этих полей. Я прочитал много статей о связи между фрагментами, но я не чувствую себя комфортно, как другие предпочитают, поэтому, подумав о том, как я должен это сделать в моем случае, я, наконец, начинаю думать о том, чтобы использовать одномодовый модельный объект, который все фрагменты могут легко получить к его полям и заполнить их конкретными шагами.
Поскольку я новичок в android, я хочу услышать от экспертов об использовании singleton вместо передачи данных между фрагментами, такими как реализованный интерфейс (кажется, это так сложно и сложно поддерживать). Любые советы будут полезны.
Ответы
Ответ 1
Хотя одноэлементный подход кажется простым в реализации и понимает, что это не лучший способ добиться того, что вам нужно. Одна из причин заключается в том, что ваш объект модели или, как вы называете его бизнес-объектом, живет вне контекста активности, который может затруднить поиск ошибок. Например. в случае, когда более одного экземпляра вашего класса активности создается системой, и оба сохраняют ссылку на ваш синглтон. Посмотрите, как вы теряете отслеживание своих объектов?
Что бы я сделал,
- Сделайте объект модели для
Parcelable
, вы будете ненавидеть его в начале, но как только вы его используете, он станет вашим модель лучший друг
- Так как ваша модель
Parcelable
теперь вы можете легко передать ее между фрагментами, действиями и даже сохранить их в общих настройках. Важно отметить, что когда вы передаете Parcelable
между фрагментом или активностью, это похоже на пропуск по значению, т.е. каждый раз, когда создается новый экземпляр.
-
Задайте аргумент фрагмента или он уже создан, затем получите аргументы и добавьте вашу модель. вот пример:
если фрагмент еще не активен:
Bundle args = new Bundle();
args.putParcable("businessObject", yourBusinessObjectThatIsParcable);
yourFragment.setArguments(args);
В противном случае: yourFragment.getArguments().putParcelable("businessObject", yourBusinessObjectThatIsParcable);
-
В вашем фрагменте, возможно, в методе onCreateView получите свой объект модели, подобный этому MyParcableObject mpo = (MyParcableObject)getArguments().getParcelable("businessObject")
, и используйте его, чтобы установить любые нужные вам данные.
-
Когда вы закончите редактировать свой объект при нажатии кнопки или в методе onPause, обновите аргументы фрагмента таким же образом getArguments().putParcelable("businessObject", mpo);
-
на последней странице или последнем фрагменте вы можете передать свой объект своей деятельности, здесь, как это сделать
Несмотря на то, что он выглядит громоздким, но это практика, вам нужно привыкнуть к разработчику Android. Вы получаете намного больше контроля, когда ваша модель реализует Parcelable
.
Другой способ сделать то, что вам нужно, - это Delegation Pattern, но в основном используется для обратных вызовов, даже если вы также можете передавать объекты.
Ответ 2
Я бы не рекомендовал глобальный синглтон. Существуют две основные причины:
- По определению, singleton ограничивает ваше приложение одним экземпляром основного бизнес-объекта. Если вы (или дизайнер, или босс босс босс) когда-либо решили иметь несколько из этих ViewPagers за один раз, вам все равно придется менять свою архитектуру.
- "Мысль Android" должна ожидать, что ваш пользователь может разместить ваше приложение в фоновом режиме и использовать другие приложения, прежде чем вернуться в ваше приложение. Если система решит убить ваше приложение в фоновом режиме, ваш объект памяти singleton будет уничтожен, и ваш пользователь потеряет все свои успехи. Правильный способ сохранения состояния Android - это сохранить состояние в Activity или Fragment, соответственно сохранить его в
onSaveInstanceState()
и восстановить его в onCreate()
.
Все фрагменты в ViewPager могут получить ссылку на родительскую активность через вызов getActivity()
. Или если ваш ViewPager находится внутри фрагмента, тогда все фрагменты могут обращаться к родительскому фрагменту через вызов getParentFragment()
. Затем вы можете передать результат в соответствующий класс (или, еще лучше, интерфейс) и сделать вызовы методов для передачи данных взад и вперед. Отслеживайте свои бизнес-данные в родительской активности/фрагменте. Таким образом, вам не нужен глобальный синглтон
Например,
public class MyParentFragment extends Fragment {
private String mPageOneData;
private int mPageTwoData;
private List<Date> mPageThreeData;
public void setPageOneData(String data) {
mPageOneData = data;
}
...
}
public class PageOneFragment extends Fragment {
private void sendDataToParent(String data) {
Fragment f = getParentFragment();
if (f != null && f instanceof MyParentFragment) {
MyParentFragment parent = (MyParentFragment) f;
f.setPageOneData(data);
}
}
}
Ответ 3
-
вы можете сохранить свои данные в событии onSaveInstanceState() в случае, если ваш процесс перейдет в фоновый режим.
вы можете восстановить свои данные в событии onCreate(), используя Bundle и getExtras().
-
вы можете сохранить свои данные в классе приложения, и данные все равно будут присутствовать, если ваш процесс перейдет в фоновый режим.
Я предпочитаю первый вариант, потому что вы не хотите создавать беспорядок в классе приложения со всеми данными из разных действий и фрагментов.
Надеюсь, я смогу помочь:)
Ответ 4
Вы проверили EventBus?
Я не уверен, что это лучший подход, особенно когда ваш вопрос слишком широк, однако это будет здорово всего с 5 фрагментами.
Надеюсь, что это поможет
Ответ 5
Я полагаю, что в вашем MainActivity есть ViewPager
, а FragmentOne
будет одним из фрагментов внутри пейджера представления. Здесь MainActivity связывается с FragmentOne, чтобы обновить адаптер. Надежда понятна.
В свой MainActivity добавьте этот интерфейс:
public interface Updateable {
public void update();
}
Внедрите этот интерфейс в фрагмент, который необходимо обновить, и напишите код, чтобы уведомить адаптер внутри метода update
:
public class FragmentOne extends Fragment implements MainActivity.Updateable {
...
@Override
public void update() {
// YOUR CODE TO UPDATE HERE, FOR EXAMPLE, HERE I'M UPDATING THE ADAPTER
if ( adapter != null ) {
adapter.notifyDataSetChanged();
} else {
Log.d("LOG_TAG", "null");
}
}
...
}
Вызвать метод update
из MainActivity, когда сначала загружается фрагмент. Вы можете сделать это, переопределяя метод getItemPosition
в PagerAdapter
, например:
@Override
public int getItemPosition(Object object) {
if ( object != null && object instanceof FragmentOne ) {
FragmentOne f = (FragmentOne) object;
f.update();
}
return super.getItemPosition(object);
}
Наконец, вы должны вызвать notifyDataSetChanged() вашего адаптера viewPager. Это заставит адаптер вашего viewpager вызвать метод getItemPosition.
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int previousState;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if (previousState == ViewPager.SCROLL_STATE_SETTLING && state == ViewPager.SCROLL_STATE_IDLE) {
if ( viewPagerAdapter.getItem(viewpager.getCurrentItem()) instanceof Pictures ) {
Log.d("LOG_TAG", "New Position=" + viewpager.getCurrentItem());
viewPagerAdapter.notifyDataSetChanged();
}
}
previousState = state;
}
});
Ответ 6
Прежде чем выбрать какой-либо вариант, имейте в виду, что пользователь может перемещаться или открывать любые другие приложения, чтобы вы потеряли свои данные.
Вы можете использовать onSaveInstanceState
, но это будет как-то сложно поддерживать (как вы сказали, вы новичок в андроиде). Вы можете использовать один синглтон, используя
- База данных. Используйте, когда вы хотите хранить несколько записей, но вам нужно создать базу данных getter/setter или использовать любой ORM, такой как RushOrm и т.д.
-
SharefPreference
(желательно) - Если вы хотите использовать одиночные значения.
В обоих случаях вы создадите одноэлементный объект и получите доступ к его свойствам в своих фрагментах.
Ответ 7
сделайте ваши объекты разумными, а затем передайте их другим фрагментам с помощью пакета. i.e bundle.putParcelable(obj) parcelable очень эффективен и быстр.
он должен мотивировать вас
http://www.developerphil.com/parcelable-vs-serializable/