2017-02-16 3 views
0

Только одна из многих проблем с фрагментами. Метод Activity.onCreate() Я инициализирую ViewPager с двумя Fragments в нем.Второй фрагмент ViewPager еще не создан

viewPager = (ViewPager) findViewById(R.id.viewpager); 
    viewPager.setOffscreenPageLimit(1); 
    adapter = new ViewPagerAdapter(getSupportFragmentManager()); 
    adapter.addFragment(new AutoFragment(), getString(R.string.song_header_automatic)); 
    adapter.addFragment(new ManualFragment(), getString(R.string.song_header_manual)); 
    adapter.notifyDataSetChanged(); 
    viewPager.setAdapter(adapter); 

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); 
    tabLayout.setupWithViewPager(viewPager); 

После этого мне нужно выполнить действие на View во втором Фрагмент ViewPager.

((Fragment) adapter.getItem(1)).getView().findViewById(...) 

Но это дает NPE, так как пользователь никогда не просматривает второй фрагмент, поэтому он еще не был присоединен. Таким образом, доступ к элементу первого фрагмента не создает проблем.

Не следует setOffscreenPageLimit(1) Способ подскажите Android, чтобы сделать также второй фрагмент?

Я также пытался не называть супер метод destroyItem внутри адаптера, но не повезло, так как проблема в том, что фрагмент даже не инициализирован.

public class ViewPagerAdapter extends FragmentStatePagerAdapter { 
    private final List<Fragment> mFragmentList = new ArrayList<>(); 
    private final List<String> mFragmentTitleList = new ArrayList<>(); 

    public ViewPagerAdapter(FragmentManager manager) { 
     super(manager); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return mFragmentList.get(position); 
    } 

    @Override 
    public int getCount() { 
     return mFragmentList.size(); 
    } 

    public void addFragment(Fragment fragment, String title) { 
     mFragmentList.add(fragment); 
     mFragmentTitleList.add(title); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     return mFragmentTitleList.get(position); 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) {} 
} 

Как я могу заставить его также визуализировать невидимый фрагмент?

ПРИМЕЧАНИЕ: эта проблема возникает только для пользователей приложений, и я не могу ее воспроизвести. Только после того, как у меня возникла эта проблема, я думаю, что все это связано с выполнением ошибочной операции после правильного события жизненного цикла.

+0

Просто попробуйте использовать 'FragmentPagerAdapter' вместо' FragmentStatePagerAdapter' –

+0

@EduardoHerzer любая идея, почему это должно решить проблему? – fillobotto

+0

проверить ответ ... слишком долго, чтобы быть комментарием –

ответ

0

В документации FragmentStatePagerAdapter:

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

Вместо этого вы можете использовать FragmentPagerAdapter.

Edit:

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

Возможно, вы попытаетесь перезагрузить второй фрагмент, передав ему аргументы.

В адаптере, реализовать метод, который заменяет фрагмент:

public void replaceFragment(int index, Fragment fragment, String title) { 
    mFragmentList.set(index, fragment); 
    mFragmentTitleList.add(index, title); 
} 

Если вы хотите, чтобы перезагрузить второй фрагмент с передаваемыми данными, просто сделать:

Bundle fragmentArgs = new Bundle(); 
fragmentArgs.putSerializable("obj", obj); //data you want to pass 
fragmentArgs.putString("str", str); //data you want to pass 
ManualFragment manualFragment = new ManualFragment(); 
manualFragment.setArguments(fragmentArgs); 

adapter.replaceFragment(1, manualFragment, getString(R.string.song_header_manual)); 
adapter.notifyDataSetChanged(); 

Тогда в onCreateView из ManualFragment, получить аргументы:

Object obj = (Object) getArguments().getSerializable("obj"); 
String str = getArguments().getString("str"); 

И делать w что бы вы ни делали.

Edit 2:

Поскольку ОП хочет другой подход, здесь идет ...

ли что-то вроде этого ответа: https://stackoverflow.com/a/24343211/2174489

Таким образом, вы не получите доступ вид с другого фрагмента вне первоначальной области. Мне не нравится идея получить как ((Fragment) adapter.getItem(1)).getView().findViewById(...). Я бы предпочел сделать ((Fragment) adapter.getItem(1)).setTextViewText(...).

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

public void setTextViewText(String value){ 
    if (mTextView == null) 
     myGlobalValue = value; 
    else 
     mTextView.setText(value); 
} 

Тогда в onCreateView, вы можете установить это значение:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    ... 
    if (myGlobalValue != null) 
     mTextView.setText(myGlobalValue); 
    ... 
} 

Позвольте мне знать, если это решит проблему.

+0

Интересно. Я дам обновление бета-версии и посмотрю, появится ли проблема снова. – fillobotto

+0

К сожалению, проблема не устранена. Это звучит скорее как фрагмент, но он не привязан к действию. – fillobotto

+0

@fillobotto. Я отредактировал ответ. Возможно, вы можете попробовать этот подход –