Pobieranie bieżącej instancji Fragmentu w przeglądarce

210

Poniżej znajduje się mój kod, z którego 3 Fragment classeskażdy jest osadzony na każdej z 3 zakładek ViewPager. Mam opcję menu. Jak pokazano w onOptionsItemSelected(), wybierając opcję, muszę zaktualizować fragment, który jest obecnie widoczny. Aby to zaktualizować, muszę wywołać metodę z klasy fragmentów. Czy ktoś może zasugerować, jak wywołać tę metodę?

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();
      }

     }

    }

Załóżmy, że poniżej znajduje się klasa fragmentów z metodą, updateList()którą chcę wywołać:

 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
    }
}
stóg
źródło
którą metodą fragmentu chcesz wywołać?
Biraj Zalavadia,
@BirajZalavadia Moja własna metoda, która zawiera parametr i używa zmiennych instancji tej klasy fragmentów, które zostały już zainicjowane podczas tworzenia nawet widoku.
rick
1
czy możesz podać nazwę klasy swoich fragmentów, które są w przeglądarce?
Biraj Zalavadia,
jakieś rozwiązanie stackoverflow.com/questions/7379165/…
An-droid
Najprostszym sposobem uzyskania dostępu do widocznych fragmentów byłoby skorzystanie z stackoverflow.com/questions/7379165/... , spójrz na dwie pierwsze odpowiedzi.
Luksprog,

Odpowiedzi:

205

wybierając opcję, muszę zaktualizować fragment, który jest obecnie widoczny.

Prostym sposobem na to jest użycie triku związanego z FragmentPagerAdapterimplementacją:

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;

Proszę przemyśleć konwencję nazewnictwa zmiennych, używając jako nazwy zmiennej nazwy klasy bardzo mylące (więc nie ViewPager ViewPager, użyj ViewPager mPagerna przykład).

Luksprog
źródło
23
Czy ten fragment fragmentu jest przyszłościowy, jeśli API się zmieni?
Maarten
7
@ Maarten Nie, to zwykły hack, który był używany od czasu pojawienia się adaptera (a jego kod źródłowy był dostępny), nie zmienił się jeszcze. Jeśli chcesz czegoś bardziej niezawodnego, musisz użyć innych opcji, z których najważniejsze to zastąpienie instantiateItem()metody i samodzielne uzyskanie referencji do odpowiednich fragmentów.
Luksprog
5
Po godzinach frustracji i pytaniu stron bezpośrednio z mAdapter.getItem(position)niesamowitego ... Przynajmniej teraz wiem, że inne próby 8512 nie zadziałały. Dzięki
Diolor
29
Uwaga: to nie działa, jeśli użyjesz FragmentStatePagerAdapter zamiast FragmentPagerAdapter.
Shawn Lauzon
3
@ShawnLauzon FragmentStatePagerAdapter ma inną implementację, w tym przypadku wywołujesz metodę instantiateItem (), aby uzyskać widoczne fragmenty.
Luksprog,
155
    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);
        }
    }
Mindphaser
źródło
28
Google powinien zapewnić FragmentPageAdapter.getCurrentPrimaryItem () zwracając mCurrentPrimaryItem.
eugene
1
Używam również tej techniki, definiuję również PagerFragment metodami onPageSelected/ onPageDeselectedi wszystkie moje fragmenty pagera go rozszerzają. Następnie setPrimaryitemmoże odpowiednio wywołać te metody, gdy użytkownik przesunie się na nową stronę. Oznacza to, że możesz wdrożyć leniwszą strategię ładowania danych na stronach, które nawet nie są wyświetlane. Należy jednak pamiętać, że podczas przenoszenia strony lepiej wygląda, jeśli następna strona jest już zapełniona danymi, więc leniwe ładowanie wszystkich danych onPageSelectedmoże nie być idealne.
JHH,
3
Dlaczego ifoświadczenie? Fragment po prostu wywołuje equalsmetodę obiektu, czyli płytkie porównanie. Dlaczego więc nie zawsze dzwonić mCurrentFragment = ((Fragment) object);?
Overclover
wypróbowałem i działa dobrze, wystarczy rzutować getCurrentFragment () na konkretny fragment, który powinien
PhilipJ
113

Przede wszystkim śledź wszystkie „aktywne” fragmenty stron. W takim przypadku śledzisz strony fragmentów w FragmentStatePagerAdapter, który jest używany przez ViewPager.

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

Aby uniknąć utrzymywania odniesienia do „nieaktywnych” stron fragmentów, musisz zaimplementować metodę destroyItem (...) FragmentStatePagerAdapter:

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

a kiedy musisz uzyskać dostęp do aktualnie widocznej strony, zadzwoń:

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

Gdzie metoda getFragment (int) MyAdapter wygląda następująco:

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

Mam nadzieję, że to może pomóc!

FraZer
źródło
Czy możesz wyjaśnić to jasno? Gdzie muszę przechowywać tę klasę FragmentStatePagerAdapter w moim kodzie? BTW Mam 3 klasy fragmentów, nie pojedyncze MyFragmentClass.
rick
7
Jeszcze lepiej, jeśli zaktualizujesz mPageReferenceMap w instantiateItem zamiast getItem, ponieważ działa również po zmianie orientacji. „@Override public Object instantiateItem (kontener ViewGroup, pozycja int) {Fragment fragment = (Fragment) Super.instantiateItem (kontener, pozycja); mPageReferenceMap.put (pozycja, fragment); fragment zwrotny; } '
pmellaaho
Jakim typem jest mPageReferenceMap?
DoruAdryan
10
Ta odpowiedź jest naprawdę zła! Nie powinieneś ręcznie przechowywać pamięci podręcznej ViewPager, ponieważ obsługuje go on sam. ViewPager decyduje, kiedy fragment powinien zostać przydzielony, czy nie, co należy wstrzymać, a kiedy zachowanie odwołania do każdego fragmentu doda trochę niepotrzebnego narzutu i nie będzie zoptymalizowane pod kątem pamięci.
Livio,
3
Wypróbowałem to podejście, ale niestety nie działa ono po odtworzeniu działania. Na Androidzie N i nowszych możesz to zobaczyć podczas korzystania z funkcji wielu okien. Gdy aplikacja jest otwarta, przytrzymaj długo przycisk „ostatnie” (kwadratowy). Aktywność i fragment są odtwarzane z saveInstanceState, adapter jest odtwarzany (więc mPageReferenceMap jest teraz pusty), ale getItem nie jest ponownie wywoływany. Mapa pozostaje pusta, więc adapter.getFragment (indeks) ulegnie awarii.
Martin Konicek,
102

Jest to jedyny sposób, w jaki nie otrzymuję NullPointerException dla zmiennych instancji tej konkretnej klasy fragmentu. Może to być pomocne dla innych, którzy utknęli przy tym samym. W onOptionsItemSelected () kodowałem poniżej:

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);
}
stóg
źródło
3
Myślę, że jest to najbardziej poprawna odpowiedź - dopasuj do projektu FragmentStatePagerAdapterbez zastępowania żadnego kodu. W rzeczywistości powinna być tak prosta, jak funkcja po prostu powraca viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang,
39

FragmentStatePagerAdapter ma metodę publiczną o nazwie instantiateItem, która zwraca fragment na podstawie określonych wartości parametrów, ta metoda ma dwa parametry ViewGroup (ViewPager) i pozycję.

public Object instantiateItem(ViewGroup container, int position);

Użyłem tej metody, aby uzyskać fragment określonej pozycji,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);
Krunal Shah
źródło
5
Ale to nie zwraca bieżącego, już utworzonego fragmentu, ale nowy, nie? Tak więc nazwa „instancja” ...
Ixx,
1
@ Ixx Nie, nie tworzy nowego fragmentu. Myślę, że nazwa metody jest tutaj niepoprawna.
Błędy występowały
15

Wiem, że jest za późno, ale mam naprawdę proste sposoby, aby to zrobić,

// dla fragmentu przy 0 pozycjach

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();
Pratik Mhatre
źródło
10

Jest tu wiele odpowiedzi, które tak naprawdę nie odnoszą się do podstawowego faktu, że tak naprawdę NIE MA SPOSOBU, aby to zrobić w sposób przewidywalny, i w sposób, który nie spowoduje, że w pewnym momencie w przyszłości strzelisz sobie w stopę.

FragmentStatePagerAdapterjest jedyną klasą, która wie, jak niezawodnie uzyskać dostęp do fragmentów, które są śledzone przez FragmentManager- każda próba odgadnięcia identyfikatora lub tagu fragmentu nie jest wiarygodna, długoterminowa. Próby ręcznego śledzenia instancji prawdopodobnie nie będą działać dobrze, gdy stan zostanie zapisany / przywrócony, ponieważ FragmentStatePagerAdaptermoże nie wywoływać wywołań zwrotnych po przywróceniu stanu.

Jedyną rzeczą, którą udało mi się wykonać, jest skopiowanie kodu FragmentStatePagerAdapteri dodanie metody, która zwraca fragment, biorąc pod uwagę pozycję ( mFragments.get(pos)). Zauważ, że ta metoda zakłada, że ​​fragment jest faktycznie dostępny (tj. Był widoczny w pewnym momencie).

Jeśli jesteś szczególnie żądny przygód, możesz użyć refleksji, aby uzyskać dostęp do elementów prywatnej mFragmentslisty, ale wrócimy do pierwszego punktu (nazwa listy nie jest taka sama).

Melllvar
źródło
1
aby poradzić sobie z „nie działa dobrze, gdy stan jest zapisany / przywrócony”, przesłaniam metodę saveState (). Aby pager nie zapisywał żadnego fragmentu, gdy aktywność jest wstrzymana. to działa.
AntoineP
2
To tylko dodaje patchworku, nie rozwiązując problemu. Nie twierdzę, że to nie działa - po prostu, że nie jest to dobra implementacja.
Melllvar,
8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Prześlij instancję odzyskaną z powyższej linii do fragmentu, nad którym chcesz pracować. Działa idealnie dobrze.

viewPager

to instancja pager zarządzająca fragmentami.

Gaurav Pangam
źródło
Działa to tylko wtedy, gdy wszystkie strony są ładowane jako Fragment. Gdy istnieje na przykład tablayout z wieloma kartami / stronami, nie wszystkie z nich są ładowane, więc może to spowodować wyjątek indexoutofbounce.
progNewbie
@progNewbie tak, który będzie wymagał dodatkowego kodu obejścia.
Gaurav Pangam,
@progNewbie Odpowiedź Evgeny'a poniżej poradziłaby sobie z tą sytuacją, myślę
Gaurav Pangam
7

wybierając opcję, muszę zaktualizować fragment, który jest obecnie widoczny.

Aby uzyskać odniesienie do aktualnie widocznego fragmentu, załóż, że masz odniesienie do ViewPageras mPager. Następnie następujące kroki otrzymają odniesienie do currentFragment:

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

Jedynie użyta obsada 3 linii jest zwykle ważna. FragmentStatePagerAdapterjest przydatnym adapterem do ViewPager.

użytkownik4665465
źródło
7

Najlepszym sposobem na to, po prostu wywołaj fragment CallingFragmentName = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Ponownie utworzy instancję twojego fragmentu wywołującego, aby nie zgłaszał wyjątku zerowego wskaźnika i nie wywoła żadnej metody tego fragmentu.

Ritesh Adulkar
źródło
6

Aktualny fragment:

Działa to, jeśli utworzyłeś projekt z szablonem paska zakładek fragmentów.

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

Zauważ, że działa to z domyślną implementacją szablonu działania z zakładkami.

Hasan
źródło
30
Zależy to od implementacji getItem () - może zwrócić nową instancję fragmentu, co prawdopodobnie nie jest tym, czego chcesz.
Tom
Tak to robisz. jeśli nadal masz domyślną konfigurację podczas tworzenia projektu tabor z fragmentami. nikt nie miał tego rozwiązania. więc pomyślałem, że to pomoże.
hasan
3

Użyłem następujących:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);
prawdziwe 19
źródło
1
Zależy to od niestandardowej implementacji pagera z odpowiedzi znalezionej tutaj: stackoverflow.com/questions/8785221/...
Tom Redman
1
Właśnie to próbowałem zrobić, ale nie wiedząc, które metody zastąpić, zmarnowałyby godziny - dzięki!
Bron Davies,
2

FragmentStatePagerAdapterma zmienną instancji prywatnej o nazwie mCurrentPrimaryItemtype Fragment. Można się tylko zastanawiać, dlaczego deweloperzy Androida nie dostarczyli go z getterem. Ta zmienna jest tworzona w setPrimaryItem()metodzie. Zastąp więc tę metodę, aby uzyskać odniesienie do tej zmiennej. Po prostu skończyłem z zadeklarowaniem własnego mCurrentPrimaryItemi skopiowaniem treści setPrimaryItem()do mojego zastąpienia.

W swojej realizacji 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;
}
Sevastyan Savanyuk
źródło
2

Można zdefiniować PagerAdapterjak to wtedy będzie w stanie uzyskać żadnej Fragmentin ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

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

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Aby uzyskać prąd Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());
Phan Van Linh
źródło
2

Gdy korzystamy z viewPager, dobrym sposobem na uzyskanie dostępu do instancji fragmentu w działaniu jest instantiateItem (viewpager, indeks). // indeks - indeks fragmentu, którego chcesz instancji.

na przykład uzyskuję dostęp do instancji fragmentu 1 indeksu

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}
Chahat Jain
źródło
1

Miałem ten sam problem i rozwiązałem go za pomocą tego kodu.

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

Wystarczy zastąpić nazwę MyFragment nazwą swojego fragmentu i dodać identyfikator kontenera fragmentów.

Bilal Soomro
źródło
1

Jest to bardziej przyszłościowe niż przyjęta odpowiedź:

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
    /* ------------------------------------------------------------------------------------------ */
}
Tim Autin
źródło
Zamiast tego powinieneś użyć WeakHashMap.
Prakash Nadar
1

Omawiany scenariusz jest lepiej obsługiwany przez każdy Fragment dodający własne pozycje menu i bezpośrednio obsługujący onOptionsItemSelected (), jak opisano w oficjalnej dokumentacji . Lepiej unikać nieudokumentowanych sztuczek.

Y2i
źródło
Ta odpowiedź może przydać się więcej szczegółów, jak to zrobić. W jaki sposób dodanie pozycji menu rozwiązuje ViewPagerproblem?
Suragch,
@Suragch ViewPager występuje, jeśli zdarzenia menu są obsługiwane w działaniu, które hostuje fragmenty, i nie występuje, jeśli zdarzenia są obsługiwane w samym fragmencie. Link pokazuje, jak fragment może dodawać własne elementy menu.
Y2i
1

Po przeczytaniu wszystkich komentarzy i odpowiedzi wyjaśnię optymalne rozwiązanie tego problemu. Najlepszą opcją jest rozwiązanie @ rik, więc moja poprawa jest oparta na jego.

Zamiast pytać o to jak każdy FragmentClass

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

Utwórz własny interfejs i spraw, aby fragmenty dziecka zaimplementowały go, coś w rodzaju

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

Następnie możesz zrobić coś takiego, aby zainicjować i zaktualizować swoje wewnętrzne fragmenty.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Zachowaj ostrożność, gdy umieścisz ten kod, jeśli wywołasz insatiateItem przed faktycznym utworzeniem go przez system, savedInstanceStatefragment Twojego dziecka będzie pusty

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

Awaria Twojej aplikacji.

Powodzenia

Pedro Varela
źródło
1

W oparciu o to, na co odpowiedział @chahat jain:

„Gdy korzystamy z viewPager, dobrym sposobem na uzyskanie dostępu do instancji fragmentu w działaniu jest instantiateItem (viewpager, indeks). // indeks-indeks fragmentu, którego chcesz instancję.”

Jeśli chcesz to zrobić w Kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 do fragmentu fragmentu 0

// ================================================ ========================= // // ##################### ######## Przykład zastosowania ############################################### // // == ================================================== ===================== //

Oto kompletny przykład najsłabszej wizji

oto mój veiewPager w pliku .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

I aktywność domowa, w której wstawiam kartę

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}
DINA TAKLIT
źródło
1

W mojej poprzedniej implementacji zapisałem listę Fragmentów potomnych, aby mieć do nich dostęp później, ale okazało się, że była to niewłaściwa implementacja powodująca ogromne wycieki pamięci.

W końcu używam instantiateItem(...)metody, aby uzyskać aktualny fragment:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Lub uzyskać inny Fragment na pozycji:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

Z dokumentacji :

Utwórz stronę dla danej pozycji. Adapter jest odpowiedzialny za dodanie widoku do podanego tutaj kontenera, ale musi tylko upewnić się, że zostanie to zrobione do czasu powrotu z finishUpdate (ViewGroup).

Micer
źródło
0

W mojej działalności mam:

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);
}
J. Musyoka
źródło
0
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());
  }
});

Czasami fragment może wywołać pusty obiekt, więc można uruchomić nowy plik Runnable, aby rozwiązać problem przy pierwszym ładowaniu.

Dziękuję Rick

Benjamín Rengifo
źródło
Dodaj tekst wyjaśniający, dlaczego ten kod rozwiązałby problem PO. Ponadto, biorąc pod uwagę liczbę innych odpowiedzi, wyjaśnij, dlaczego ta odpowiedź jest lepsza niż te, które już podano. Pomóż innym zrozumieć.
APC,
0

Przesłoń setPrimaryItem z Twojego FragmentPagerAdapter: obiekt jest widocznym fragmentem:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }
Flavio Barisi
źródło
0

Wystarczy pobrać bieżący element z pagera, a następnie poprosić adapter o fragment tej pozycji.

 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;
    }
Pankaj Kumar
źródło
3
Co jeśli getItemutworzy nową instancję
Prakash Nadar
0

Aby uzyskać bieżący fragment - uzyskaj pozycję w ViewPager w public void onPageSelected (końcowa pozycja int) , a następnie

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 - argument pozycji przypisany publicznie statyczny PlaceholderFragment newInstance (int sectionNumber); fragmentu

getChildFragmentManager () lub getFragmentManager () - zależy od tego, jak utworzono SectionsPagerAdapter

Evgeny
źródło
0

Możesz zaimplementować BroadcastReceiver we fragmencie i wysłać zamiar z dowolnego miejsca. Odbiornik fragmentu może nasłuchiwać określonej akcji i wywoływać metodę instancji.

Jednym zastrzeżeniem jest upewnienie się, że komponent View jest już utworzony i (a dla niektórych operacji, takich jak przewijanie listy, ListView musi być już zrenderowany).

nichole
źródło
0

To najprostszy hack:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(kod kotlin)

Wystarczy zadzwonić instantiateItem(viewPager, viewPager.getCurrentItem()i przesłać na Fragment. Twój przedmiot zostałby już utworzony. Dla pewności możesz dodać czek dla getCount.

Działa zarówno z, jak FragmentPagerAdapteri FragmentStatePagerAdapter!

wedant
źródło
0

Jeśli twój pager znajduje się we fragmencie, użyj tego:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Gdzie R.id.myViewPagerIdjest identyfikator twojego ViewPager w układzie xml.

vovahost
źródło
Działa to tylko z normalnym FragmentPageAdapter, a nie z FragmentStatePageAdapter.
progNewbie
0

Możesz zadeklarować tablicę fragmentów jako fragmenty rejestru

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Następnie możesz użyć go jako

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}
Hamza Khan
źródło
Jeśli zdecydujesz się pójść tą drogą, powinieneś również zaimplementować destroyItem () i usunąć zniszczoną instancję z registerFragments, w przeciwnym razie wyciek pamięci.
dephinera
To dobra rada. Możesz dokonać edycji w odpowiedzi.
Hamza Khan