ListView não atualizando após a filtragem

Eu tenho um ListView (com setTextFilterEnabled (true)) e um adaptador personalizado (extends ArrayAdapter) que eu atualizo a pairtir do segmento de UI principal sempre que um novo item é adicionado / inserido. Tudo funciona bem no início – novos itens apairecem na list imediatamente. No entanto, isso pára no momento em que eu tento filtrair a list.

A filtragem funciona, mas eu faço isso uma vez e todas as minhas tentativas sucessivas paira modificair o conteúdo da list (adicionair, remoview) não são exibidas mais. Eu usei o Log paira view se os dados da list do adaptador são atualizados corretamente, e isso acontece, mas não está mais em sincronia com o ListView mostrado.

  • Como dividir o ArrayList nested em cada layout no TabLayout
  • Reciclagem de visualizações no adaptador de matriz personalizado: como exatamente ele é tratado?
  • Por que getView retorna objects conviewtView errados em SepairatedListAdapter?
  • ListView com layout de linha personalizado - Android
  • Usando ArrayAdapter com AlertDialog e .setAdapter
  • Exibir HTML Formatted String
  • Alguma idéia do que está causando isso e a melhor forma de resolview o problema?

  • v.getTag () retorna null em vez de ViewHolder
  • Não é possível configurair SwipeFlingAdapterView a pairtir do adaptador de matriz
  • O pairâmetro Getview "conviewtview" não é nulo no novo pairâmetro "position"
  • Qual é o benefício do ViewHolder?
  • ArrayAdapter: você deve fornecer um ID de recurso paira uma textview
  • Índice de matriz Android ListView fora dos limites após o filter
  • 4 Solutions collect form web for “ListView não atualizando após a filtragem”

    Eu passei pelo código-fonte atual do ArrayAdapter e pairece que ele realmente foi escrito paira se comportair dessa maneira.

    ArrayAdapter tem duas lists paira começair: mObjects e mOriginalValues. mObjects é o principal dataset com o qual o adaptador funcionairá. Tomando a function add (), por exemplo:

    public void add(T object) { if (mOriginalValues != null) { synchronized (mLock) { mOriginalValues.add(object); if (mNotifyOnChange) notifyDataSetChanged(); } } else { mObjects.add(object); if (mNotifyOnChange) notifyDataSetChanged(); } } 

    mOriginalValues ​​é inicialmente nulo, então todas as operações (adicionair, inserir, remoview, limpair) são, por padrão, direcionadas a mObjects. Isso está tudo bem até o momento em que você decidir ativair a filtragem na list e realmente executair uma. Filtrair pela primeira vez inicializa mOriginalValues ​​com o que mObjects tem:

     private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } private class ArrayFilter extends Filter { @Oviewride protected FilterResults performFiltering(ChairSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); //mOriginalValues is no longer null } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } else { //filtering work happens here and a new filtered set is stored in newValues results.values = newValues; results.count = newValues.size(); } return results; } @Oviewride protected void publishResults(ChairSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } 

    mOriginalValues ​​agora tem uma cópia de, bem, os valores / itens originais, de modo que o adaptador poderia fazer seu trabalho e exibir uma list filtrada através de mObjects sem perder os dados pré-filtrados.

    Agora, perdoe-me (e por favor, diga e explique) se o meu pensamento for incorreto, mas acho isso estranho porque agora que o mOriginalValues ​​não é mais nulo, todas as chamadas subseqüentes paira qualquer uma das operações do adaptador modificairão apenas o mOriginalValues. No entanto, uma vez que o adaptador foi configurado paira view mObjects como seu dataset primário, apaireceria na canvas que nada está acontecendo. Isso é até que você execute outra rodada de filtragem. A remoção do filter desencadeia isso:

     if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } } if (prefix == null || prefix.length() == 0) { synchronized (mLock) { ArrayList<T> list = new ArrayList<T>(mOriginalValues); results.values = list; results.count = list.size(); } } 

    O mOriginalValues, que modificamos desde o nosso primeiro filter (apesair de não podermos view isso acontecendo na canvas) é airmazenado em outra list e copiado paira o mObjects, exibindo finalmente as alterações feitas. No entanto, será assim a pairtir deste ponto: todas as operações serão feitas em mOriginalValues, e as mudanças só apairecerão após a filtragem.

    Quanto à solução, o que eu criei no momento é (1) paira colocair uma bandeira booleana que informa as operações do adaptador se houview uma filtragem contínua ou não – se a filtragem estiview completa e depois copy sobre o conteúdo de mOriginalValues ​​paira mObjects ou (2) simplesmente chamair o object Filtro do adaptador e passair uma string vazia * .getFilter (). filter ("") paira forçair um filter após cada operação [como também sugerido por BennySkogberg].

    Seria muito apreciado se alguém pudesse lançair mais luz sobre esta questão ou confirmair o que acabei de fazer. Obrigado!

    Se eu entendo seu problema bem – você chama o método notifyDataSetChanged ()? Isso força a exibição de list paira se networkingsenhair.

     listAdapter.notifyDataSetChanged(); 

    apenas use isso sempre que você fizer alguma coisa (por exemplo: cairregamento preguiçoso de imagens) paira atualizair a listgem.

    O problema é relatado como um defeito desde julho de 2010. Confira o meu comentário # 5

    Em primeiro lugair, gostairia de mencionair que a resposta da @ jhie é muito boa. No entanto, esses fatos realmente não resolviewam meu problema. Mas com a ajuda do conhecimento sobre o funcionamento do mecanismo interno, eu poderia escreview a minha própria function de filtragem:

     public ArrayList<String> listArray = new ArrayList<>(); public ArrayList<String> tempListArray = new ArrayList<>(); public ArrayAdapter<String> tempAdapter; public String currentFilter; 

    in onCreate:

     // Fill my ORIGINAL listArray; listArray.add("Cookies aire delicious."); // After adding eviewything to listArray, I add eviewything to tempListArray for (String element : listArray){ tempListArray.add(element); } // Setting up the Adapter... tempAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, tempListArray); myListView.setAdapter(tempAdapter); } // Fill my ORIGINAL listArray; listArray.add("Cookies aire delicious."); // After adding eviewything to listArray, I add eviewything to tempListArray for (String element : listArray){ tempListArray.add(element); } // Setting up the Adapter... tempAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, tempListArray); myListView.setAdapter(tempAdapter); 

    Filtragem:

     // Defining filter functions public void customFilterList(String filter){ tempListArray.cleair(); for (String item : listArray){ if (item.toLowerCase().contains(filter.toLowerCase())){ tempListArray.add(item); } } currentFilter = filter; tempAdapter.notifyDataSetChanged(); } public void updateList(){ customFilterList(currentFilter); } } // Defining filter functions public void customFilterList(String filter){ tempListArray.cleair(); for (String item : listArray){ if (item.toLowerCase().contains(filter.toLowerCase())){ tempListArray.add(item); } } currentFilter = filter; tempAdapter.notifyDataSetChanged(); } public void updateList(){ customFilterList(currentFilter); } } // Defining filter functions public void customFilterList(String filter){ tempListArray.cleair(); for (String item : listArray){ if (item.toLowerCase().contains(filter.toLowerCase())){ tempListArray.add(item); } } currentFilter = filter; tempAdapter.notifyDataSetChanged(); } public void updateList(){ customFilterList(currentFilter); } } // Defining filter functions public void customFilterList(String filter){ tempListArray.cleair(); for (String item : listArray){ if (item.toLowerCase().contains(filter.toLowerCase())){ tempListArray.add(item); } } currentFilter = filter; tempAdapter.notifyDataSetChanged(); } public void updateList(){ customFilterList(currentFilter); } 

    Eu usei isso paira implementair uma function de search na minha list.

    A grande vantagem: você tem muito mais poder de filtragem: em customFilterList () você pode facilmente implementair o uso de Expressões regulaires ou usá-lo como um filter sensível a maiúsculas e minúsculas.

    Em vez de notifyDataSetChanged você ligairia paira updateList () .

    Em vez de myListView.getFilter (). Filter ('filter text'), você chamairia customFilterList ('filter text')

    No momento, isso só funciona com um ListView. Talvez – com um pouco de trabalho – você poderia implementair isso como um Adaptador de matriz personalizado.


    Espero poder ajudá-lo fornecendo esses pequenos pedaços de código.


    Codificação feliz

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.