Obtendo a instância atual do Fragment no viewpager


210

Abaixo está o meu código, que foi 3 Fragment classesincorporado a cada uma das 3 guias ViewPager. Eu tenho uma opção de menu. Como mostrado na onOptionsItemSelected(), selecionando uma opção, preciso atualizar o fragmento que está visível no momento. Para atualizar que eu tenho que chamar um método que está na classe de fragmento. Alguém pode sugerir como chamar esse método?

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

     }

    }

Suponha que abaixo está a classe de fragmento com o método que updateList()eu quero chamar:

 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
    }
}

qual método de fragmento você deseja chamar?
Biraj Zalavadia

@BirajZalavadia Meu próprio método definido, que possui um parâmetro e usa as variáveis ​​de instância dessa classe de fragmento que já foram inicializadas enquanto criamos uma view even.
Rick

1
você pode dar o nome da classe dos seus fragmentos que estão no visor?
Biraj Zalavadia


A maneira mais simples de acessar os fragmentos visíveis seria através de stackoverflow.com/questions/7379165/… , veja as duas principais respostas.
Luksprog

Respostas:


205

selecionando uma opção, preciso atualizar o fragmento que está visível no momento.

Uma maneira simples de fazer isso é usar um truque relacionado à FragmentPagerAdapterimplementação:

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;

Por favor, repensar sua convenção de nomenclatura de variáveis, usando como nome da variável o nome da classe é muito confuso (portanto ViewPager ViewPager, não , use ViewPager mPagerpor exemplo).


23
Essa tag de fragmento é à prova de futuro, se a API mudar?
Maarten

7
@Maarten Não, é apenas um truque comum que foi usado desde que o adaptador apareceu (e seu código-fonte estava disponível), ainda não mudou. Se você quiser algo mais confiável, precisará usar outras opções, principalmente a substituição do instantiateItem()método e a obtenção de referências aos fragmentos adequados.
precisa saber é o seguinte

5
Depois de horas de frustração e pedindo as páginas diretamente da mAdapter.getItem(position), incrível ... Pelo menos agora eu sei que os outros 8512 ensaios não funcionaram. Obrigado
Diolor

29
Observe que isso não funciona se você usar FragmentStatePagerAdapter em vez de FragmentPagerAdapter.
Shawn Lauzon

3
@ShawnLauzon O FragmentStatePagerAdapter possui uma implementação diferente; nesse caso, você chama seu método instantiateItem () para obter os fragmentos visíveis.
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);
        }
    }

28
O Google deve fornecer FragmentPageAdapter.getCurrentPrimaryItem () retornando mCurrentPrimaryItem.
Eugene

1
Eu também uso essa técnica. Também defino um PagerFragment com métodos onPageSelected/ onPageDeselectede todos os meus fragmentos de pager o estendem. Em seguida, você setPrimaryitempode chamar esses métodos adequadamente quando o usuário passar para uma nova página. Isso significa que você pode implementar uma estratégia mais lenta para carregar dados em páginas que nem são mostradas. No entanto, você deve ter em mente que, durante a transição da página, parecerá melhor se a próxima página já estiver preenchida com dados; portanto, o carregamento lento de todos os dados onPageSelectedpoderá não ser o ideal.
JHH

3
Por que a ifdeclaração? O fragmento apenas chama o equalsmétodo do objeto, que é uma comparação superficial. Então, por que nem sempre ligar mCurrentFragment = ((Fragment) object);?
Overclover

tentei e funciona bem, basta converter o getCurrentFragment () para o fragmento específico que deveria
PhilipJ

113

Antes de tudo, acompanhe todas as páginas de fragmentos "ativas". Nesse caso, você acompanha as páginas do fragmento no FragmentStatePagerAdapter, usado pelo ViewPager.

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

Para evitar manter uma referência a páginas de fragmento "inativas", é necessário implementar o método destroyItem (...) do FragmentStatePagerAdapter:

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

e quando você precisar acessar a página visível no momento, ligue para:

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

Onde o método getFragment (int) do MyAdapter se parece com o seguinte:

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

Espero que ajude!


Você pode explicar claramente? Onde preciso manter essa classe FragmentStatePagerAdapter no meu código? BTW eu tenho 3 classes de fragmentos, não único MyFragmentClass.
Rick

7
Melhor ainda, se você atualizar o mPageReferenceMap em instantiateItem, em vez de getItem, porque também funciona após a alteração da orientação. '@Override public Object instantiateItem (container ViewGroup, int position) {Fragmento fragmento = (Fragmento) Super.instantiateItem (container, posição); mPageReferenceMap.put (posição, fragmento); fragmento de retorno; } '
pmellaaho 13/02/2014

Que tipo é mPageReferenceMap?
DoruAdryan

10
Esta resposta é muito ruim! Você não deve manter o cache de um ViewPager manualmente, pois ele o manipula sozinho. O ViewPager decide quando o fragmento deve ser alocado ou não, o que pausar e quando, manter uma referência em cada fragmento adicionará uma sobrecarga inútil e não será otimizada para a memória.
Livio

3
Eu tentei essa abordagem, mas infelizmente ela não funciona quando a atividade é recriada. No Android N e posterior, você pode ver isso ao usar o recurso de várias janelas. Quando o aplicativo estiver aberto, mantenha pressionado o botão 'Recentes' (o quadrado). A atividade e o fragmento são recriados de savedInstanceState, o adaptador é recriado (portanto, o mPageReferenceMap agora está vazio), mas getItem não é chamado novamente. O mapa permanece vazio e o adaptador.getFragment (index) falha.
Martin Konicek

102

Essa é a única maneira de não obter NullPointerException para as variáveis ​​de instância dessas classes de fragmento em particular. Isso pode ser útil para outras pessoas que ficaram com a mesma coisa. No onOptionsItemSelected (), codifiquei da maneira abaixo:

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

3
Eu acho que essa é a resposta mais correta - alinhe-se com o design do FragmentStatePagerAdaptersem substituir nenhum código. De fato, deve ser tão simples quanto uma função apenas retornar viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang

39

FragmentStatePagerAdapter possui um método público com o nome instantiateItem que retorna seu fragmento com base nos valores de parâmetros especificados, esse método possui dois parâmetros ViewGroup (ViewPager) e position.

public Object instantiateItem(ViewGroup container, int position);

Usou esse método para obter o fragmento da posição especificada,

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

5
Mas isso não retorna o fragmento já instanciado, mas um novo, não? Assim nomeie "instanciar" ...
Ixx

1
@Ixx Não, ele não cria um novo fragmento. Acho que o nome do método está incorreto aqui.
Erros acontecem

15

Sei que é tarde demais, mas tenho maneiras muito simples de fazê-lo,

// para fragmento na posição 0

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

10

Há muitas respostas aqui que realmente não abordam o fato básico de que não há NENHUMA MANEIRA de fazer isso de forma previsível, e de uma maneira que não resulte em um tiro no pé em algum momento no futuro.

FragmentStatePagerAdapteré a única classe que sabe como acessar de maneira confiável os fragmentos rastreados pelo FragmentManager- qualquer tentativa de tentar adivinhar o ID ou a tag do fragmento não é confiável a longo prazo. E as tentativas de rastrear as instâncias manualmente provavelmente não funcionarão bem quando o estado for salvo / restaurado, pois FragmentStatePagerAdapterpode não chamar os retornos de chamada quando o estado for restaurado.

A única coisa que pude fazer funcionar é copiar o código FragmentStatePagerAdaptere adicionar um método que retorna o fragmento, dada uma posição ( mFragments.get(pos)). Observe que esse método pressupõe que o fragmento esteja realmente disponível (ou seja, estava visível em algum momento).

Se você é particularmente aventureiro, pode usar a reflexão para acessar os elementos da mFragmentslista particular , mas voltamos à estaca zero (o nome da lista não garante a mesma).


1
para lidar com o "não funciona bem quando o estado é salvo / restaurado", substituo o método saveState (). Para que o pager não salve nenhum fragmento quando a atividade estiver em pausa. funciona.
AntoineP

2
Isso apenas aumenta a colcha de retalhos, sem corrigir o problema subjacente. Não estou argumentando que não funcione - apenas que não é uma boa implementação.
Melllvar

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Transmitir a instância recuperada da linha acima para o fragmento em que você deseja trabalhar. Funciona perfeitamente bem.

viewPager

é a instância do pager que gerencia os fragmentos.


Isso funciona apenas se todas as páginas forem carregadas como fragmento. Quando há, por exemplo, um tablayout com muitas guias / páginas, nem todos são carregados, portanto, isso pode gerar uma exceção de indexação de rejeição.
progNewbie

@progNewbie sim, isso precisará de um código de solução extra.
Gaurav Pangam

A resposta de @progNewbie Evgeny abaixo iria lidar com essa situação eu acho
Gaurav Pangam

7

selecionando uma opção, preciso atualizar o fragmento que está visível no momento.

Para obter uma referência ao fragmento visível no momento, suponha que você tenha uma referência a ViewPagercomo mPager. Em seguida, as etapas a seguir obterão uma referência para currentFragment:

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

A única linha usada do elenco 3 é válida normalmente. FragmentStatePagerAdapteré um adaptador útil para um ViewPager.


7

A melhor maneira de fazer isso é chamar o fragmento CallingFragmentName = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Ele instanciará novamente seu fragmento de chamada, para que não atinja uma exceção de ponteiro nulo e chame qualquer método desse fragmento.


6

Fragmento atual:

Isso funciona se você criou um projeto com o modelo da barra de tabulação de fragmentos.

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

Observe que isso funciona com a implementação padrão do modelo de atividade com guias.


30
Isso depende da sua implementação de getItem () - pode retornar uma nova instância do fragmento, que provavelmente não é o que você deseja.
Tom

É assim que você faz. se você ainda tiver a configuração padrão ao criar um projeto tabor com fragmentos. nenhum tinha essa solução. então eu pensei que iria ajudar.
Hasan

3

Eu usei o seguinte:

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

1
Isso depende de uma implementação pager personalizado a partir da resposta encontrada aqui: stackoverflow.com/questions/8785221/...
Tom Redman

1
Era exatamente isso que eu estava tentando fazer, mas sem saber quais métodos substituir, teria perdido horas - obrigado!
Bron Davies

2

FragmentStatePagerAdaptertem uma variável de instância privada chamada mCurrentPrimaryItemdo tipo Fragment. Só podemos nos perguntar por que os desenvolvedores do Android não forneceram um getter. Essa variável é instanciada no setPrimaryItem()método Portanto, substitua esse método para que você obtenha a referência a essa variável. Acabei declarando minha própriamCurrentPrimaryItem e copiando o conteúdo desetPrimaryItem() para a minha substituição.

Na sua implementação de 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;
}

2

Você pode definir o PagerAdaptercomo este, em seguida, você será capaz de obter qualquer Fragmentno 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);
    }
}

Para obter a corrente Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Quando usamos o viewPager, uma boa maneira de acessar a instância do fragmento em atividade é instantiateItem (viewpager, index). // index-index do fragmento do qual você deseja instância.

por exemplo, estou acessando a instância de fragmento de 1 index-

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

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

}

1

Eu tive o mesmo problema e o resolvi usando esse código.

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

Apenas substitua o nome MyFragment pelo nome do seu fragmento e adicione o ID do seu contêiner de fragmento.


1

Isso é mais à prova do futuro do que a resposta aceita:

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
    /* ------------------------------------------------------------------------------------------ */
}

Você deve usar o WeakHashMap.
Prakash Nadar

1

O cenário em questão é melhor atendido por cada fragmento, adicionando seus próprios itens de menu e manipulando diretamente onOptionsItemSelected (), conforme descrito na documentação oficial . É melhor evitar truques não documentados.


Esta resposta pode usar mais detalhes sobre como realmente fazer isso. Como a adição de um item de menu resolve o ViewPagerproblema?
Suragch

O problema do @Suragch ViewPager existe se os eventos do menu forem manipulados na Activity que hospeda fragmentos e não existe se os eventos forem manipulados no próprio fragmento. O link mostra como um fragmento pode adicionar seus próprios itens de menu.
Y2i 3/11

1

Depois de ler todos os comentários e respostas, vou explicar uma solução ideal para esse problema. A melhor opção é a solução da @ rik, então minha melhoria é baseada na dele.

Em vez de precisar perguntar a cada FragmentClass como

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

Crie sua própria interface e faça com que seus fragmentos filhos a implementem, algo como

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

Então, você pode fazer algo assim para iniciar e atualizar seus fragmentos internos.

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

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

PS Cuidado ao colocar esse código, se você chamar insatiateItem antes que o sistema realmente o crie, o savedInstanceStatefragmento de seu filho será nulo.

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

Irá travar seu aplicativo.

Boa sorte


1

Com base no que ele respondeu @chahat jain:

"Quando usamos o viewPager, uma boa maneira de acessar a instância do fragmento em atividade é instantiateItem (viewpager, index). // index-index do fragmento do qual você deseja instância."

Se você quer fazer isso no kotlin

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

0 0 para a instância de fragmento de 0

// ================================================== ========================= // // ##################### ######## Exemplo de usos ################################## // // == ==================================================== ===================== //

Aqui está um exemplo completo para obter uma visão perdida sobre

aqui está o meu veiewPager no arquivo .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"/>
    ...

E a atividade em casa onde insiro a guia

...
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)
    }
        ...

}

1

Na minha implementação anterior, eu armazenei uma lista de fragmentos filhos para poder acessá-los mais tarde, mas isso acabou sendo uma implementação errada, causando enormes vazamentos de memória.

Acabo usando o instantiateItem(...)método para obter o fragmento atual:

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

Ou para obter qualquer outro fragmento na posição:

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

Da documentação :

Crie a página para a posição especificada. O adaptador é responsável por incluir a visualização no contêiner fornecido aqui, embora apenas seja necessário garantir que isso seja feito no momento em que ele retorne de finishUpdate (ViewGroup).


0

Na minha atividade eu tenho:

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

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

Às vezes, o fragmento pode despachar um objeto nulo, para que você possa executar um novo Runnable para resolver o problema no primeiro carregamento.

Obrigado Rick


Por favor, adicione algum texto explicando por que esse código resolveria o problema do OP. Além disso, considerando quantas outras respostas existem, explique por que essa resposta é melhor do que as já fornecidas. Ajude os outros a entender.
APC

0

Substitua setPrimaryItem do FragmentPagerAdapter: o objeto é o fragmento visível:

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

0

Simplesmente obtenha o item atual do pager e peça ao seu adaptador o fragmento dessa posição.

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

3
E se getItemcriar uma nova instância?
Prakash Nadar

0

Para obter o fragmento atual - obtenha a posição no ViewPager em public void onPageSelected (final int position) e, em seguida,

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 - argumento de posição atribuído em estático público PlaceholderFragment newInstance (int sectionNumber);de fragmento

getChildFragmentManager () ou getFragmentManager () - depende de como foi criado o SectionsPagerAdapter


0

Você pode implementar um BroadcastReceiver no fragmento e enviar uma intenção de qualquer lugar. O receptor do fragmento pode ouvir a ação específica e invocar o método da instância.

Uma ressalva é garantir que o componente View já esteja instanciado e (e para algumas operações, como rolar uma lista, o ListView já deve ser renderizado).


0

Este é o hack mais simples:

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

(código kotlin)

Basta ligar instantiateItem(viewPager, viewPager.getCurrentItem()e lançar para Fragment. Seu item já seria instanciado. Para ter certeza de que você pode adicionar uma verificação getCount.

Funciona com ambos FragmentPagerAdaptere FragmentStatePagerAdapter!


0

Se o seu pager estiver dentro de um fragmento, use o seguinte:

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

Onde R.id.myViewPagerIdestá o ID do seu ViewPager dentro do Layout xml.


Isso funciona apenas com o FragmentPageAdapter normal e não com o FragmentStatePageAdapter.
progNewbie

0

Você pode declarar uma matriz de fragmento como registrar fragmentos

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
    }

}

Então você pode usá-lo como

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Se você decidir seguir esse caminho, implemente também destroyItem () e remova a instância destruída de RegisteredFragments; caso contrário, haverá um vazamento de memória.
dephinera 19/03

Esse é um bom conselho. Você pode fazer uma edição na resposta.
Hamza Khan

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.