exemplo notifyDataSetChanged


166

Eu estou tentando usar no meu Android Applicationo notifyDataSetChanged()método para um ArrayAdapter, mas ele não funciona para mim.

Eu encontrei como resposta aqui , que notifyDataSetChanged()deve ser executado no thread principal, mas não havia exemplo para isso.

Alguém poderia enviar um exemplo ou pelo menos um link ?!



você pode verificar este blogue e este exemplo no github e isso também
Cabezas

Respostas:


328

Para um ArrayAdapter, notifyDataSetChangedsó funciona se você usar o add(), insert(), remove(), e clear()no adaptador.

Quando um ArrayAdapteré construído, ele mantém a referência do Listque foi passado. Se você fosse passar um Listque era membro de uma Atividade e alterá-lo mais tarde, ele ArrayAdapterainda mantém uma referência ao original List. O adaptador não sabe que você alterou o Listna atividade.

Suas escolhas são:

  1. Use as funções do ArrayAdapterpara modificar a lista subjacente ( add(), insert(), remove(), clear(), etc.)
  2. Recrie o ArrayAdaptercom os novos Listdados. (Usa muitos recursos e coleta de lixo.)
  3. Crie sua própria classe derivada BaseAdaptere ListAdapterque permita a alteração da Listestrutura de dados subjacente .
  4. Use notifyDataSetChanged()sempre que a lista for atualizada. Para chamá-lo no UI-Thread, use o runOnUiThread()de Activity. Então, notifyDataSetChanged()vai funcionar.

13
tenha cuidado também de atribuir objetos 'novos' aos seus dados. usar clear () em vez disso, repovoar / fazer alterações aos dados, em seguida, chamar notifyDataSetChanged ()
moonlightcheese

Mas e se chamarmos notifyDataSetChanged()dessa maneira ((BaseAdapter) arrayAdapter).notifyDataSetChanged();:?
TeoREtik

2
Eu uso BaseExpandableListAdapter, ele não tem funções add () ou remove (), então eu armazeno meu mapa como uma variável de membro. Eu atualizo o Map e ligo para notifyDatasetChanged (), mas nada acontece. Quando eu uso a opção nº 4, ela funciona. Por quê???
Emeraldhieu # 25/12

Estou usando ArrayAdapter para GridView personalizado, estou adicionando imagens à medida que as obtenho de URLs, chamando adapter.add (dataReceived). Isso funciona bem adiciona dados, mas por que é refrescante e vai para o topo. Quero mostrar os itens, pois eles serão adicionados sem atualizar a lista. (O que você quer fazer é trabalhar com o GridView do Android usando notifyDatasetChanged ()) Como fazê-lo funcionar neste customGridView (StaggeredGridView).
MobileEvangelist

1
Tentei criar meu próprio BaseAdapter para adicionar métodos de classificação à lista, mas por algum motivo isso simplesmente não funcionou. Não que meu aplicativo seja lento, mesmo que eu recrie todo o adaptador com uma lista de matrizes classificada, mas ainda me irrita. Como exatamente isso criaria muito lixo? Suponho que a matriz real de dados dispendiosos seja mantida como uma referência na atividade que chama o adaptador, o que significa que apenas o adaptador será coletado.
G_V

34

Você pode usar o runOnUiThread()método da seguinte maneira. Se você não estiver usando a ListActivity, basta adaptar o código para obter uma referência ao seu ArrayAdapter.

final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }
});

1
Tentei adicionar o seu fragmento de código no meu código (você pode encontrá-lo aqui stackoverflow.com/questions/3667442/how-to-refresh-adapter ) no método onCreate, mas ainda não tenho sucesso :( talvez fosse lugar errado para adicioná-lo ?!
Tima

1
Sua pergunta acabou de perguntar como você poderia chamar o método e executá-lo no thread principal da interface do usuário. Isso responde a essa pergunta. No seu caso específico ( stackoverflow.com/questions/3670500/… ), o AsyncTask e seu método onPostExecute () parecem ser o que você deve considerar.
Brian

12

Eu escrevi recentemente sobre esse tópico, embora este post seja antigo, achei que seria útil para alguém que deseja saber como implementar BaseAdapter.notifyDataSetChanged()passo a passo e de maneira correta.

Siga Como implementar corretamente BaseAdapter.notifyDataSetChanged () no Android ou o blog mais recente BaseAdapter.notifyDataSetChanged () .


Olá, eu tentei o primeiro exemplo de link, mas, em vez de mItem.add(), eu fiz apenas a edição de um elemento, mItem.get(position).setImage(encodedImage)pode ser que seja por isso que está dando a exceção de NullPointer de erro. somente para add (), clear (), remove () etc #
Shreekant N

notifyDataSetChanged funcionará para editar ou modificar o conjunto de dados, seu ponteiro nulo é por causa de outra coisa, verifique os logs.
Arif Nadeem

7

Eu tive o mesmo problema e prefiro não substituir o ArrayAdapter inteiro por uma nova instância continuamente. Portanto, eu tenho o AdapterHelper fazendo o trabalho pesado em outro lugar.

Adicione isto onde você normalmente (tentaria) ligar para notificar

new AdapterHelper().update((ArrayAdapter)adapter, new ArrayList<Object>(yourArrayList));
adapter.notifyDataSetChanged();

Classe AdapterHelper

public class AdapterHelper {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void update(ArrayAdapter arrayAdapter, ArrayList<Object> listOfObject){
        arrayAdapter.clear();
        for (Object object : listOfObject){
            arrayAdapter.add(object);
        }
    }
}

Eu tenho alguns outros ArrayAdapters no meu código e eles funcionaram sem problemas. Hoje à noite, decidi transformar um SimpleCursorAdapter em um ArrayAdapter, e NÃO FUNCIONARIA. Depois de lutar por algumas horas e tentar encontrar um motivo pelo qual não funcionaria, encontrei sua classe AdapterHelper e AGORA AGORA FUNCIONA! Obrigado!
Proudgeekdad

1
Isso pode ser feito facilmente em uma função ... POR QUE você instanciaria uma nova classe para ela?
techiServices

2
Em Java, as funções são chamadas métodos. O que você propõe, tem esse método altamente reutilizável na mesma classe que o Array Adapter, talvez? Ou o fragmento / atividade que contém a exibição de lista? Então, sim, está em uma classe onde pode ser reutilizado. Se você quiser torná-lo estático, vá em frente.
Kevin Parker

1
Boa ideia. Outro seria estender o ArrayAdapter, chamado ArrayAdapterCompat e substituir o método addAll (..), já que este está disponível apenas desde a API 11. Lá, verifique o nível da API e use super.addAll(..)API> 11 e super.add (.. ) em combinação com iteração como a sua: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { super.addAll(items); } else { for (Object o : collection) { super.add(o); } }. Agora basta estender sua nova classe de adaptadores.
Konsumierer 26/10/12

Perfeito! Muito obrigado @ Kevin - era exatamente isso que eu precisava!
Kibi

3

Sei que esta é uma resposta tardia, mas estava enfrentando um problema semelhante e consegui resolvê-lo usando notifyDataSetChanged()no lugar certo.

Então, minha situação era a seguinte.

Eu tive que atualizar uma exibição de lista em uma guia da barra de ação (fragmento) com o conteúdo retornado de uma atividade completamente diferente. Inicialmente, no entanto, a exibição de lista não refletia nenhuma alteração. No entanto, ao clicar em outra guia e retornar à guia desejada, a exibição da lista seria atualizada com o conteúdo correto da outra atividade. Então, para resolver isso, usei notifyDataSetChanged()o adaptador da barra de ação no código da atividade que teve que retornar os dados.

Este é o trecho de código que eu usei na atividade.

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) 
    {
        case R.id.action_new_forward:

            FragmentTab2.mListAdapter.notifyDataSetChanged();//this updates the adapter in my action bar tab
            Intent ina = new Intent(getApplicationContext(), MainActivity.class);
            ina.putExtra("stra", values1);
            startActivity(ina);// This is the code to start the parent activity of my action bar tab(fragment).
    }
}

Essa atividade retornaria alguns dados FragmentTab2e atualizaria diretamente minha listview em FragmentTab2.

Espero que alguém ache isso útil!

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.