2017-02-17 11 views
16

У меня есть 5 фрагментов в ViewPager, которые используются для заполнения бизнес-объекта несколькими полями шаг за шагом, на каждом шаге будут установлены некоторые из этих полей. Я прочитал много статей о связи между фрагментами, но я не чувствую себя комфортно, как другие предпочитают, поэтому, подумав о том, как я должен это сделать в моем случае, я, наконец, начинаю думать о том, чтобы использовать одномодовый модельный объект, который все фрагменты могут легко получить к своим полям и заполнить их конкретными шагами.Объекты связи между несколькими фрагментами в ViewPager

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

+0

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

+0

I не знаете вашу точную проблему, но подумали ли вы использовать интерфейсы между фрагментами (и использовать их внутри OnPageChangeListener)? –

+0

Да, это дорого и слишком сложно реализовать этот общий интерфейс в деятельности, фрагменты, просмотрщик и бла-бла-бла. подумайте о том, что вам нужно изменить приоритет шагов или добавить дополнительные шаги между шагами. – saber

ответ

5

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

Что бы я сделал это

  1. Сделать моя модель объекта для реализации Parcelable вы будете ненавидеть его в начале, но как только вы получите использовать для него это станет лучшим другом вашей модели
  2. Поскольку ваша модель parcelable теперь вы можете легко передать его между фрагментами, действиями и даже сохранить его в общих настройках. Важно отметить, что при передаче parcelable между фрагментом или активностью это похоже на пропуск по значению, т. Е. Каждый раз, когда создается новый экземпляр.
  3. Задайте аргумент фрагмента или, если он уже создан, получите аргументы и добавьте вашу модель.вот пример: если фрагмент не активен еще:

    Bundle args = new Bundle(); args.putParcable("businessObject", yourBusinessObjectThatIsParcable); yourFragment.setArguments(args);

    В противном случае: yourFragment.getArguments().putParcelable("businessObject", yourBusinessObjectThatIsParcable);

  4. В вашем фрагменте, возможно в методе onCreateView получить объект модели, как этот MyParcableObject mpo = (MyParcableObject)getArguments().getParcelable("businessObject") и использовать его установить какие данные вы хотите.

  5. Когда вы закончите редактирование объекта на нажатие кнопки или в методе OnPause обновленные аргументы вашего фрагмента таким же образом getArguments().putParcelable("businessObject", mpo);

  6. в вашей последней странице или последний фрагмент вы можете передать свой объект в вашей деятельности, here является как

Хотя это выглядит громоздким, но это практика, с которой вам нужно привыкнуть как разработчик Android. Вы получаете больше контроля, когда ваша модель реализует parcelable.

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

1

Я полагаю, что в вашем 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; 
     } 
    }); 
+0

Спасибо за ваши усилия, но, к сожалению, это не соответствует моим требованиям. У меня есть одна активность и фрагмент внутри него, внутри фрагмента активности есть viewpager, а viewpager имеет свои собственные фрагменты для каждой страницы. Думаю, я должен пойти с синглтон, который более ясен и прост в обслуживании. – saber

+0

Тот же подход, который я использовал с Activity и Fragment, можно использовать с вашей ситуацией (фрагмент с пейджером представления и фреймворком внутри пейджера просмотра).Тем не менее, вы согласны, если он подходит или нет –

6

Я бы не рекомендовал глобальный синглтон. Существуют две основные причины:

  1. По определению одноточие ограничивают ваше приложение одним экземпляром основного бизнес-объекта. Если вы (или дизайнер, или босс босса босса) когда-либо решили иметь несколько этих ViewPagers за раз, вам все равно придется менять свою архитектуру.
  2. «Способ мышления 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); 
    } 
    } 

} 
1

Прежде чем выбрать любой вариант, иметь в виду, пользователь может перемещаться или открыть любое другое приложение (ы), так что вы потеряли ваши данные.

Вы можете использовать onSaveInstanceState, но это будет как-то сложно поддерживать (как вы сказали, вы новичок в андроиде). Вы можете пойти с с одноплодной помощью

  • базы данных - Используется, когда вы хотите сохранить поддерживать несколько записей, но вы должны создать базу данных геттер/сеттер или использовать ORM, как RushOrm и т.д.
  • SharefPreference (предпочтительно) - Если вы хотите использовать одиночные значения.

В обоих случаях вы создадите одноэлементный объект и получите доступ к его свойствам в своих фрагментах.

3
  1. Вы можете сохранить свои данные в событии onSaveInstanceState(), если ваш процесс перейдет в фоновый режим. вы можете восстановить свои данные в событии onCreate(), используя Bundle и getExtras().

  2. Вы можете сохранить свои данные в классе приложений, и данные все равно будут присутствовать на вашем фоне.

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

2

У вас есть чек EventBus?

Я не уверен, что это лучший подход, особенно когда ваш вопрос слишком широк, однако это будет здорово только с 5 фрагментами.

Надеется, что это помогает

1

Сделайте ваши объекты разумными, а затем передайте их другим фрагментам, используя пучок. i.e bundle.putParcelable (obj) parcelable очень эффективен и быстр.

это должно мотивировать вас

http://www.developerphil.com/parcelable-vs-serializable/