Получение текущего экземпляра фрагмента в viewpager

Ниже мой код, который имеет 3 Fragment classes каждый из которых встроен в каждую из трех вкладок в ViewPager . У меня есть опция меню. Как показано в onOptionsItemSelected() , выбирая опцию, мне нужно обновить фрагмент, который в настоящее время виден. Чтобы обновить это, я должен вызвать метод, который находится в классе фрагмента. Может кто-нибудь предложить, как назвать этот метод?

 public class MainActivity extends ActionBarActivity { ViewPager ViewPager; TabsAdapter TabsAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewPager = new ViewPager(this); ViewPager.setId(R.id.pager); setContentView(ViewPager); final ActionBar bar = getSupportActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); //Attaching the Tabs to the fragment classes and setting the tab title. TabsAdapter = new TabsAdapter(this, ViewPager); TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"), FragmentClass1.class, null); TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"), FragmentClass2.class, null); TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"), FragmentClass3.class, null); if (savedInstanceState != null) { bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0)); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.addText: **// Here I need to call the method which exists in the currently visible Fragment class** return true; } return super.onOptionsItemSelected(item); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex()); } public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener { private final Context mContext; private final ActionBar mActionBar; private final ViewPager mViewPager; private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); static final class TabInfo { private final Class<?> clss; private final Bundle args; TabInfo(Class<?> _class, Bundle _args) { clss = _class; args = _args; } } public TabsAdapter(ActionBarActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; mActionBar = activity.getSupportActionBar(); mViewPager = pager; mViewPager.setAdapter(this); mViewPager.setOnPageChangeListener(this); } public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) { TabInfo info = new TabInfo(clss, args); tab.setTag(info); tab.setTabListener(this); mTabs.add(info); mActionBar.addTab(tab); notifyDataSetChanged(); } @Override public void onPageScrollStateChanged(int state) { // TODO Auto-generated method stub } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // TODO Auto-generated method stub } @Override public void onPageSelected(int position) { // TODO Auto-generated method stub mActionBar.setSelectedNavigationItem(position); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // TODO Auto-generated method stub } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { Object tag = tab.getTag(); for (int i=0; i<mTabs.size(); i++) { if (mTabs.get(i) == tag) { mViewPager.setCurrentItem(i); } } tabPosition = tab.getPosition(); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { // TODO Auto-generated method stub } @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); return Fragment.instantiate(mContext, info.clss.getName(), info.args); } @Override public int getCount() { return mTabs.size(); } } } 

Предположим ниже, что класс фрагмента с методом updateList() я хочу вызвать:

  public class FragmentClass1{ ArrayList<String> originalData; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View fragmentView = inflater.inflate(R.layout.frag1, container, false); originalData = getOriginalDataFromDB(); return fragmentView; } public void updateList(String text) { originalData.add(text); //Here I could do other UI part that need to added } } 

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

Простой способ сделать это – использовать трюк, связанный с реализацией FragmentPagerAdapter :

 case R.id.addText: Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem()); // based on the current position you can then cast the page to the correct // class and call the method: if (ViewPager.getCurrentItem() == 0 && page != null) { ((FragmentClass1)page).updateList("new item"); } return true; 

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

Прежде всего, отслеживайте все «активные» фрагменты. В этом случае вы отслеживаете страницы фрагментов в FragmentStatePagerAdapter, который используется ViewPager.

 @Override public Fragment getItem(int index) { Fragment myFragment = MyFragment.newInstance(); mPageReferenceMap.put(index, myFragment); return myFragment; } 

Чтобы избежать ссылки на «неактивные» фрагментные страницы, вам необходимо реализовать метод destroyItem (…) FragmentStatePagerAdapter:

 @Override public void destroyItem (ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); mPageReferenceMap.remove(position); } 

И когда вам нужно получить доступ к текущей видимой странице, вы вызываете:

 int index = mViewPager.getCurrentItem(); MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter()); MyFragment fragment = adapter.getFragment(index); 

Где метод getFragment (int) MyAdapter выглядит следующим образом:

 public MyFragment getFragment(int key) { return mPageReferenceMap.get(key); } 

Надеюсь, это поможет!

  public class MyPagerAdapter extends FragmentPagerAdapter { private Fragment mCurrentFragment; public Fragment getCurrentFragment() { return mCurrentFragment; } //... @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { if (getCurrentFragment() != object) { mCurrentFragment = ((Fragment) object); } super.setPrimaryItem(container, position, object); } } 

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

 if(viewPager.getCurrentItem() == 0) { FragmentClass1 frag1 = (FragmentClass1)viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()); frag1.updateList(text); }else if(viewPager.getCurrentItem() == 1) { FragmentClass2 frag2 = (FragRecentApps)viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()); frag2.updateList(text); } 

Здесь есть много ответов, которые на самом деле не затрагивают основополагающий факт, что на самом деле нет НИКАКИХ способов сделать это предсказуемо, и таким образом, чтобы вы не стреляли в ногу в какой-то момент в будущем.

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

Единственное, что я смог сделать, это копирование кода для FragmentStatePagerAdapter и добавление метода, возвращающего фрагмент, с учетом позиции ( mFragments.get(pos) ). Обратите внимание, что этот метод предполагает, что фрагмент фактически доступен (т. Е. Он был видимым в какой-то момент).

Если вы особенно предприимчивы, вы можете использовать рефлексию для доступа к элементам частного списка mFragments , но затем мы вернемся к квадрату (имя списка не будет оставаться неизменным).

FragmentStatePagerAdapter имеет общедоступный метод с именем instantiateItem, который возвращает ваш кадр на основе заданных значений параметров, этот метод имеет два параметра ViewGroup (ViewPager) и позицию.

 public Object instantiateItem(ViewGroup container, int position); 

Используется этот метод для получения фрагмента указанной позиции,

 Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position); 

Этот код поможет мне, проверьте его.

Текущий фрагмент:

 Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem()); 

Обратите внимание, что это работает с реализацией шаблона активности вкладки по умолчанию.

Я использовал следующее:

  int index = vpPager.getCurrentItem(); MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter()); MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index); 

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

Чтобы получить ссылку на видимый в настоящее время фрагмент, предположим, что у вас есть ссылка на ViewPager как mPager . Затем следующие шаги получат ссылку на currentFragment :

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

Обычно используется только литая строка 3. FragmentStatePagerAdapter – полезный адаптер для ViewPager.

У меня была такая же проблема, и я решил использовать этот код.

 MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container); 

Просто замените имя MyFragment на имя вашего фрагмента и добавьте идентификатор вашего контейнера фрагментов.

Это более надежное будущее, чем принятый ответ:

 public class MyFragmentPagerAdapter extends FragmentPagerAdapter { /* ------------------------------------------------------------------------------------------ */ // region Private attributes : private Context _context; private FragmentManager _fragmentManager; private Map<Integer, String> _fragmentsTags = new HashMap<>(); // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Constructor : public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) { super(fragmentManager); _context = context; _fragmentManager = fragmentManager; } // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region FragmentPagerAdapter methods : @Override public int getCount() { return 2; } @Override public Fragment getItem(int position) { if(_fragmentsTags.containsKey(position)) { return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position)); } else { switch (position) { case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); } case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); } } } return null; } @Override public Object instantiateItem(ViewGroup container, int position) { // Instantiate the fragment and get its tag : Fragment result = (Fragment) super.instantiateItem(container, position); _fragmentsTags.put(position, result.getTag()); return result; } // endregion /* ------------------------------------------------------------------------------------------ */ } 

Я знаю его слишком поздно, но у меня есть очень простые способы сделать это,

// для фрагмента в 0

 ((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod(); 

В моей деятельности у меня есть:

 int currentPage = 0;//start at the first tab private SparseArray<Fragment> fragments;//list off fragments viewPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int pos) { currentPage = pos;//update current page } @Override public void onPageScrolled(int arg0, float arg1, int arg2) {} @Override public void onPageScrollStateChanged(int arg0) {} }); @Override public void onAttachFragment(Fragment fragment) { super.onAttachFragment(fragment); if(fragment instanceof Fragment1) fragments.put(0, fragment); if(fragment instanceof Fragment2) fragments.put(2, fragment); if(fragment instanceof Fragment3) fragments.put(3, fragment); if(fragment instanceof Fragment4) fragments.put(4, fragment); } Then I have the following method for getting the current fragment public Fragment getCurrentFragment() { return fragments.get(currentPage); } 
 final ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { switch (position) { case 0: FragmentClass1 frag1 = (FragmentClass1) viewPager.getAdapter() .instantiateItem(viewPager, viewPager.getCurrentItem()); frag1.updateList("Custom text"); break; case 1: break; case 2: break; } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageScrollStateChanged(int state) { } }; viewPager.addOnPageChangeListener(onPageChangeListener); viewPager.setAdapter(adapter); viewPager.post(new Runnable() { @Override public void run() { onPageChangeListener.onPageSelected(viewPager.getCurrentItem()); } }); 

Иногда фрагмент может отправлять нулевой объект, поэтому вы можете запустить новый Runnable для решения проблемы при первой загрузке.

Спасибо, Рик

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

Переопределить SetPrimaryItem из вашего FragmentPagerAdapter: объект является видимым фрагментом:

  @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { if (mCurrentFragment != object) { mCurrentFragment = (LeggiCapitoloFragment) object; } super.setPrimaryItem(container, position, object); } 

Прочитав все комментарии и ответы, я собираюсь объяснить оптимальное решение этой проблемы. Лучшим вариантом является решение @ rik, поэтому мое улучшение основывается на его.

Вместо того, чтобы спрашивать каждый FragmentClass, как

 if(FragmentClass1){ ... if(FragmentClass2){ ... } 

Создайте свой собственный интерфейс и создайте его дочерние фрагменты, что-то вроде

 public interface MyChildFragment { void updateView(int position); } 

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

 Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem()); if (childFragment != null) { ((MyChildFragment) childFragment).updateView(); } 

PS Будьте осторожны, когда вы помещаете этот код, если вы вызываете insatiateItem до того, как система фактически создаст его, savedInstanceState вашего дочернего фрагмента будет нулевым для этого

 public void onCreate(@Nullable Bundle savedInstanceState){ super(savedInstanceState) } 

Сбой приложения.

Удачи

Просто получите текущий элемент из пейджера, а затем попросите свой адаптер об этом фрагменте.

  int currentItem = viewPager.getCurrentItem(); Fragment item = mPagerAdapter.getItem(currentItem); if (null != item && item.isVisible()) { //do whatever want to do with fragment after doing type checking return; } 

Получить текущий фрагмент – получить позицию в ViewPager в public void onPageSelected (конечная позиция int) , а затем

 public PlaceholderFragment getFragmentByPosition(Integer pos){ for(Fragment f:getChildFragmentManager().getFragments()){ if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) { return (PlaceholderFragment) f; } } return null; } 

SECTNUM – аргумент позиции, назначенный публичному статическому PlaceholderFragment newInstance (int sectionNumber); Фрагмента

GetChildFragmentManager () или getFragmentManager () – зависит от того, как созданные SectionsPagerAdapter

FragmentStatePagerAdapter имеет переменную частного экземпляра, называемую mCurrentPrimaryItem типа Fragment . Можно только удивляться, почему разработчики Android не поставляли его с помощью геттера. Эта переменная setPrimaryItem() в setPrimaryItem() . Таким образом, переопределите этот метод таким образом, чтобы вы могли получить ссылку на эту переменную. Я просто закончил тем, что объявил свой собственный mCurrentPrimaryItem и копировал содержимое setPrimaryItem() в мое переопределение.

В вашей реализации FragmentStatePagerAdapter :

 private Fragment mCurrentPrimaryItem = null; @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment)object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); mCurrentPrimaryItem.setUserVisibleHint(false); } if (fragment != null) { fragment.setMenuVisibility(true); fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } } public TasksListFragment getCurrentFragment() { return (YourFragment) mCurrentPrimaryItem; }