2013-07-13 4 views
17

Я использую FragmentPagerAdapter, содержащий несколько фрагментов, которые должны быть уведомлены об изменениях в базе данных. Я делаю это путем итерации над фрагментами, которые реализуют интерфейс обратного вызова, и вызывая метод refreshData().FragmentPagerAdapter - Как обрабатывать изменения ориентации?

Это прекрасно работает, пока устройство не изменит ориентацию. После изменения ориентации пользовательский интерфейс фрагмента явно не обновляется, даже если вызов метода работает.

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

private class DataPagerAdapter extends FragmentPagerAdapter { 

    private DataFragment[] fragments = new DataFragment[] { 
            new FooDataFragment(), BarDataFragment()}; 

    public DataPagerAdapter(android.support.v4.app.FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return fragments[position]; 
    } 

    @Override 
    public int getCount() { 
     return fragments.length; 
    } 

    public DataFragment[] getFragments() { 
     return fragments; 
    } 
} 

protected void refreshData() { 
    for (DataFragment dataFragment : mPagerAdapter.getFragments()) { 
    dataFragment.refreshData(); 
} 

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

+1

добавьте в Уре activty тег в Manifest андроида: configChanges = "ориентация | Размер экрана | keyboardHidden" (Target API 13+) – TheFlash

+0

minSdkVersion 7 так что это не будет работать для меня –

ответ

52

Да, как вы сказали, FragmentManager обрабатывает фрагменты после изменения ориентации, поэтому getItem в адаптере не вызывается. Но вы можете переопределить метод instantiateItem(), который вызывается даже после изменения ориентации и отбрасывает объект в фрагмент и сохраняет его в вашем массиве.

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    DataFragment fragment = (DataFragment) super.instantiateItem(container, position); 
    fragments[position] = fragment; 
    return fragment; 
} 
+0

This выглядит аккуратно, к сожалению, поведение по-прежнему их одинаково. Я также попытался добавить android: configChanges = "ориентация" к манифесту. –

+1

Я действительно не рекомендую использовать orientantionChanges в манифесте. Итак, вы говорите, что refreshData() по-прежнему вызывает старые фрагменты? Когда вы вызываете refreshData()? Вы должны проверить, действительно ли instantiateItem() вызывается и вызывается перед методом refreshData(). – koso

+0

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

-1

У меня была аналогичная проблема, мой рабочий раствор: В деятельности, где это адаптер позвонить adapter.notifyDataSetChanged();

Переопределить метод getItemPostion() в адаптере

@Override 
    public int getItemPosition(Object object) { 
     MyFragment frag = (MyFragment)object; 
     frag.refresh(); 
     return POSITION_UNCHANGED; 
    } 

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

Затем добавьте метод refresh() в вашем фрагменте (ы) и использовать эту реализацию:

public void refresh() { 
     LayoutInflater inflater = LayoutInflater.from(getActivity()); 
     ViewGroup viewGroup = (ViewGroup) getView(); 
     viewGroup.removeAllViewsInLayout(); 
     View view = onCreateView(inflater, viewGroup, null); 
     viewGroup.addView(view); 

    } 

Это работало для меня. Мое мнение: Проблема при изменении ориентации устройства, адаптер разрушен, но фрагменты все еще находятся в памяти, и система пытается повторно использовать их после изменения ориентации, но виды, которые содержатся в фрагментах, также уничтожаются фрагменты должны быть «воссозданы» (вызов метода onCreateView). Возможно, я ошибаюсь, поэтому, пожалуйста, поправьте меня ....

(Извините за мой английский)

+0

Это решение не подходит для большинства приложений. Бывают случаи, когда андроид будет повторно создавать фрагмент от вашего имени в качестве оптимизации (например, после изменения ориентации). Это не всегда приведет к желаемым результатам - например, если вы добавите свой ViewPager за пределы действия onCreate, фрагмент получит пустой контейнер. Чтобы устранить такие проблемы, вы можете удалить фрагмент в onCreateView() {) (if (container == null) {deleteMeFromFragmentManager()) вашего фрагмента; return null; ...}. Ваш новый FragmentPageAdapter теперь воссоздает этот экземпляр фрагмента. – dzlatkov