Não consigo atualizar o conteúdo no ViewPager.
Qual é o uso correto dos métodos instantiateItem () e getItem () na classe FragmentPagerAdapter?
Eu estava usando apenas getItem () para instanciar e retornar meus fragmentos:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
Isso funcionou bem. Exceto que não posso alterar o conteúdo.
Então encontrei o seguinte: ViewPager PagerAdapter não atualizando o View
"Minha abordagem é usar o método setTag () para qualquer exibição instanciada no método instantiateItem ()"
Agora eu quero implementar o instantiateItem () para fazer isso. Mas não sei o que tenho que retornar (o tipo é Object) e qual é a relação com getItem (int position)?
Eu li a referência :
resumo público Fragmento getItem (int position)
Retorne o fragmento associado a uma posição especificada.
public Object instantiateItem (container ViewGroup, int position)
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 quando retornar de finishUpdate (ViewGroup). Parâmetros
container A vista que contém a página em que a página será exibida. position A posição da página a ser instanciada.
Devoluções
Retorna um objeto que representa a nova página. Isso não precisa ser uma Visualização, mas pode ser outro contêiner da página.
mas ainda não entendi.
Aqui está o meu código. Estou usando o pacote de suporte v4.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
Aqui também está alguém com um problema semelhante, sem respostas http://www.mail-archive.com/[email protected]/msg200477.html
Respostas:
Ao usar o FragmentPagerAdapter ou o FragmentStatePagerAdapter, é melhor lidar exclusivamente
getItem()
e não tocarinstantiateItem()
em nada. A interfaceinstantiateItem()
-destroyItem()
-isViewFromObject()
no PagerAdapter é uma interface de nível inferior que o FragmentPagerAdapter usa para implementar o muito mais simplesgetItem()
interface .Antes de entrar nisso, devo esclarecer que
Uma versão anterior desta resposta cometeu o erro de usar o FragmentPagerAdapter como exemplo - isso não funcionará porque o FragmentPagerAdapter nunca destrói um fragmento depois que ele é exibido pela primeira vez.
Eu não recomendo o
setTag()
efindViewWithTag()
solução fornecida no post é ligada. Como você descobriu, usarsetTag()
efindViewWithTag()
não funciona com fragmentos, portanto, não é uma boa combinação.A solução certa é substituir
getItemPosition()
. QuandonotifyDataSetChanged()
é chamado, o ViewPager chamagetItemPosition()
todos os itens em seu adaptador para ver se eles precisam ser movidos para uma posição diferente ou removidos.Por padrão,
getItemPosition()
retornaPOSITION_UNCHANGED
, o que significa: "Este objeto está bem onde está, não o destrua ou remova". RetornandoPOSITION_NONE
corrige o problema dizendo: "Este objeto não é mais um item que estou exibindo, remova-o". Portanto, ele tem o efeito de remover e recriar todos os itens do seu adaptador.Esta é uma correção completamente legítima! Essa correção faz o notifyDataSetChanged se comportar como um adaptador comum sem exibir a reciclagem. Se você implementar essa correção e o desempenho for satisfatório, estará pronto para a corrida. Tarefa concluída.
Se você precisar de melhor desempenho, poderá usar uma
getItemPosition()
implementação mais sofisticada . Aqui está um exemplo para um pager criando fragmentos de uma lista de strings:Com esta implementação, apenas fragmentos que exibem novos títulos serão exibidos. Quaisquer fragmentos que exibam títulos que ainda estão na lista serão movidos para sua nova posição na lista, e fragmentos com títulos que não estão mais na lista serão destruídos.
E se o fragmento não tiver sido recriado, mas precisar ser atualizado de qualquer maneira? Atualizações para um fragmento vivo são melhor tratadas pelo próprio fragmento. Essa é a vantagem de ter um fragmento, afinal - é seu próprio controlador. Um fragmento pode adicionar um ouvinte ou um observador a outro objeto
onCreate()
e removê-loonDestroy()
, gerenciando as próprias atualizações. Você não precisagetItem()
inserir todo o código de atualização como em um adaptador para um ListView ou outros tipos de AdapterView.Uma última coisa - apenas porque o FragmentPagerAdapter não destrói um fragmento, não significa que getItemPosition seja completamente inútil em um FragmentPagerAdapter. Você ainda pode usar esse retorno de chamada para reordenar seus fragmentos no ViewPager. Porém, nunca os removerá completamente do FragmentManager.
fonte
FragmentStatePagerAdapter
, posso ver que ele remove meu fragmento e cria a nova instância. Mas a nova instância recebe um BundleInstanceState salvo com o estado de um fragmento antigo. Como posso destruir completamente o fragmento para que o Bundle seja nulo quando criado novamente?Em vez de retornar
POSITION_NONE
a partirgetItemPosition()
e causando completo de recreação, faça o seguinte:Seus fragmentos devem implementar a
UpdateableFragment
interface:e a interface:
Sua classe de dados:
fonte
Fragment
dinamicamente, dê uma olhada: stackoverflow.com/questions/19891828/...d page on refreshes the 1-st page only after swiping pages? thw 2
página em 3 d estará sempre em branco. graçaspara aqueles que ainda enfrentam o mesmo problema que eu enfrentei antes quando tenho um
ViewPager
com 7 fragmentos. o padrão para esses fragmentos para carregar o conteúdo em inglês doAPI
serviço, mas o problema aqui que eu quero alterar o idioma da atividade de configurações e após concluir a atividade de configurações, queroViewPager
na atividade principal atualizar os fragmentos para corresponder à seleção de idioma do usuário e carregar o conteúdo em árabe, se o usuário escolher árabe aqui, o que eu fiz para trabalhar desde a primeira vez1- Você deve usar o FragmentStatePagerAdapter conforme mencionado acima.
2- on mainActivity, substitui o onResume e fiz o seguinte
3-i substituiu o
getItemPosition()
no mPagerAdapter e o fez retornarPOSITION_NONE
.funciona como charme
fonte
Encontrei esse problema e finalmente o resolvi hoje, então escrevo o que aprendi e espero que seja útil para alguém que seja novo no Android
ViewPager
e atualize como eu. Estou usandoFragmentStatePagerAdapter
no nível 17 da API e atualmente tenho apenas 2 fragmentos. Eu acho que deve haver algo errado, por favor me corrija, obrigado.Dados serializados devem ser carregados na memória. Isso pode ser feito usando um
CursorLoader
/AsyncTask
/Thread
. O carregamento automático depende do seu código. Se você estiver usando umCursorLoader
, ele será carregado automaticamente, pois há um observador de dados registrado.Depois de ligar
viewpager.setAdapter(pageradapter)
, o adaptadorgetCount()
é constantemente chamado para criar fragmentos. Portanto, se os dados estiverem sendo carregados, égetCount()
possível retornar 0, portanto, você não precisa criar fragmentos fictícios para nenhum dado mostrado.Depois que os dados são carregados, o adaptador não cria fragmentos automaticamente, pois
getCount()
ainda é 0, para que possamos definir o número de dados realmente carregado a ser retornadogetCount()
e depois chamar o adaptadornotifyDataSetChanged()
.ViewPager
comece a criar fragmentos (apenas os 2 primeiros) por dados na memória. É feito antes denotifyDataSetChanged()
ser retornado. Em seguida,ViewPager
tem os fragmentos certos que você precisa.Se os dados no banco de dados e a memória forem atualizados (gravação), ou apenas os dados na memória forem atualizados (gravação novamente), ou apenas os dados no banco de dados serão atualizados. Nos últimos dois casos, se os dados não forem carregados automaticamente do banco de dados para a memória (conforme mencionado acima). O
ViewPager
adaptador e pager apenas lida com dados na memória.Portanto, quando os dados na memória são atualizados, precisamos chamar os adaptadores
notifyDataSetChanged()
. Como o fragmento já foi criado, os adaptadoresonItemPosition()
serão chamados antes donotifyDataSetChanged()
retorno. Nada precisa ser feitogetItemPosition()
. Em seguida, os dados são atualizados.fonte
notifyDataSetChanged()
e apenas atualizar automaticamente, porque o fragmento (com chartview) que eu uso se atualizará. se não é, como um fragmento estático, eu vou ter que chamaronItemPositon()
e retornaPOSITION_NONE
sinto muito por issoExperimente o
destroyDrawingCache()
ViewPager depoisnotifyDataSetChanged()
no seu código.fonte
Fragments
meu pager de exibição. Então obrigado!Depois de horas de frustração ao tentar todas as soluções acima para superar esse problema e também tentar muitas soluções em outras questões semelhantes, como este , este e este que todos falharam comigo para resolver este problema e para fazer a
ViewPager
destruir o velhoFragment
e encher opager
com o novoFragment
s. Resolvi o problema da seguinte maneira:1) Faça a
ViewPager
aula estender daFragmentPagerAdapter
seguinte maneira:2) Crie um item para
ViewPager
esse armazenamentotitle
e ofragment
seguinte:3) Faça o construtor do
ViewPager
take minhaFragmentManager
instância para armazená-lo no meu daclass
seguinte maneira:4) Crie um método para redefinir o
adapter
dados com os novos dados, eliminando todos os anterioresfragment
dafragmentManager
própria diretamente para fazer aadapter
para definir o novofragment
a partir da nova lista novamente da seguinte forma:5) No contêiner
Activity
ouFragment
não reinicialize o adaptador com os novos dados. Defina os novos dados através do métodosetPagerItems
com os novos dados da seguinte maneira:Espero que ajude.
fonte
Por alguma razão, nenhuma das respostas funcionou para mim, então tive que substituir o método restoreState sem chamar super no meu fragmentStatePagerAdapter. Código:
fonte
Modifiquei levemente a solução fornecida por Bill Phillips para atender às minhas necessidades
para que os
getItemPosition()
retornosPOSITION_NONE
apenas dos fragmentos que estão atualmente noFragmentManager
quandogetItemPosition
sejam chamados. (Observe que issoFragmentStatePager
e oViewPager
associado a ele estão contidos em um fragmento que não está em uma atividade)fonte
Eu tive um problema semelhante, mas não quero confiar nas soluções existentes (nomes de códigos codificados etc.) e não consegui fazer a solução da M-WaJeEh funcionar para mim. Aqui está a minha solução:
Eu mantenho referências aos fragmentos criados no getItem em uma matriz. Isso funciona bem, desde que a atividade não seja destruída devido a configurationChange ou falta de memória ou qualquer outra coisa (-> ao retornar à atividade, os fragmentos retornam ao seu último estado sem que 'getItem' seja chamado novamente e, portanto, sem atualizar a matriz )
Para evitar esse problema, implementei o instantiateItem (ViewGroup, int) e atualizei minha matriz, assim:
Então, por um lado, estou feliz por ter encontrado uma solução que funciona para mim e queria compartilhá-la com você, mas também queria perguntar se outra pessoa tentou algo semelhante e se há alguma razão para que eu não deva. faz assim? Até agora, funciona muito bem para mim ...
fonte
myFragments
empublic void destroyItem(ViewGroup container, int position, Object object)
tão bem como você não pegar uma referência fragement obsoleto.Eu uso a biblioteca EventBus para atualizar o
Fragment
conteúdoViewPager
. A lógica é simples, assim como o documento do EventBus, como fazer . Não é necessário controlarFragmentPagerAdapter
instância. O código está aqui:1: Definir eventos
Defina qual mensagem é necessária para atualizar.
2.Prepare assinantes
Escreva o código abaixo na atualização do fragmento necessário.
3.Postar eventos
Escreva o código abaixo em outro
Activity
ou em outroFragment
que precise atualizar o parâmetrofonte
Se você deseja usar o FragmentStatePagerAdapter, consulte https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% 20Estrelas & groupby = & sort = & id = 37990 . Há problemas com o FragmentStatePagerAdapter que podem ou não causar problemas ao seu caso de uso.
Além disso, o link também tem poucas soluções ... poucos podem atender às suas necessidades.
fonte
Vivi o mesmo problema e procurei muitas vezes. Qualquer resposta dada no stackoverflow ou via google não foi a solução para o meu problema. Meu problema foi fácil. Eu tenho uma lista, mostro essa lista com o viewpager. Quando adiciono um novo elemento ao cabeçalho da lista e atualizo o nada do viewpager alterado. Minha solução final foi muito fácil de usar. Quando um novo elemento é adicionado à lista e deseja atualizar a lista. Primeiramente, defina o adaptador do viewpager como nulo, em seguida, recrie o adaptador e defina i como viewpager.
Verifique se o seu adaptador deve estender o FragmentStatePagerAdapter
fonte
Aqui está minha implementação que incorpora as informações do @Bill Phillips One, que recebe o cache de fragmentos na maioria das vezes, exceto quando os dados foram alterados. Simples e parece funcionar bem.
MyFragmentStatePagerAdapter.java
MyActivity.java
fonte
Eu estava tentando tantas abordagens diferentes, nenhuma realmente afetou meu problema. Abaixo está como eu resolvo isso com uma mistura de soluções fornecidas por todos vocês. Obrigado a todos.
Eu só quero atualizar a página 0 após onResume ().
No meu FragmentsMain, há uma "página" pública inteira, que pode me dizer se é a página que eu quero atualizar.
fonte
Eu sei que estou atrasado para o partido. Corrigi o problema ligando
TabLayout#setupWithViewPager(myViewPager);
logo apósFragmentPagerAdapter#notifyDataSetChanged();
fonte
Essa solução não funcionará para todos, mas no meu caso, cada fragmento no meu ViewPager é de classe diferente e apenas um deles existe por vez.
Com essa restrição, esta solução é segura e deve ser segura para uso na produção.
Se você tiver várias versões do mesmo fragmento, poderá usar essa mesma estratégia para chamar métodos nesses fragmentos para determinar se é o fragmento que deseja atualizar.
fonte
Isso pode ser útil para alguém - no meu caso, ao inserir uma nova página, o pager de exibição estava solicitando a posição de um fragmento existente duas vezes, mas não solicitando a posição do novo item, causando comportamento incorreto e dados não sendo exibidos.
Copie a fonte para o FragmentStatePagerAdapter (parece não ter sido atualizado há muito tempo).
Substituir notifyDataSetChanged ()
Adicione uma verificação de integridade para destroyItem () para evitar falhas:
fonte
Eu passei por todas as respostas acima e várias outras postagens, mas ainda não consegui encontrar algo que funcionasse para mim (com diferentes tipos de fragmentos, além de adicionar e remover abas dinamicamente). A abordagem a seguir da FWIW é o que funcionou para mim (caso alguém tenha os mesmos problemas).
fonte
Use FragmentStatePagerAdapter em vez de FragmentPagerAdapter se desejar recriar ou recarregar fragmentos com base no índice. Por exemplo, se você deseja recarregar fragmentos diferentes de FirstFragment, verifique a instância e retorne a posição como esta
fonte
Você precisa alterar o elemento mFragments de instantiateItem, getItemPosition.
Baseado no AndroidX FragmentStatePagerAdapter.java, porque
mFragments
a posição dos elementos não muda ao chamar notifyDataSetChanged ().Fonte: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java
Exemplo: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt
Você pode executar este projeto para confirmar como trabalhar. https://github.com/cuichanghao/infivt
fonte