2015-05-25 2 views
0

Я показываю некоторые данные в ListView, используя свой собственный класс ArrayAdapter. У меня есть счетчик в Action Bar и на основе его выбора элементов. Я хочу фильтровать данные и переписывать их в виде списка.Пользовательский ListView ArrayAdapter не отображает отфильтрованные данные

В настоящее время, когда моя активность загружается, данные отображаются правильно, но когда я выбираю любой элемент из счетчика, ListView пуст и не отображает никаких данных, хотя панель действий по-прежнему появляется.

Не могли бы вы рассказать мне, что я делаю неправильно?

Это мой обычай ArrayAdapter Класс:

public class MyAdapter extends ArrayAdapter implements Filterable { 

private ArrayList < ArrayList <String>> arrayList;  
private LayoutInflater theInflater; 

public MyAdapter(Context context, ArrayList arrayList) { 
    super(context, R.layout.row_layout, arrayList); 
    this.arrayList = arrayList; 

} 


@Override 
public View getView(int position, View convertView, ViewGroup parent) { 


    theInflater = LayoutInflater.from(getContext()); 

    View theView = theInflater.inflate(R.layout.row_layout, parent, false); 

    ArrayList <String> values = (ArrayList <String>) getItem(position); 

    TextView a= (TextView) theView.findViewById(R.id.a); 
    TextView b= (TextView) theView.findViewById(R.id.b); 
    TextView c= (TextView) theView.findViewById(R.id.c); 

    a.setText(values.get(0)); 
    b.setText(values.get(1)); 
    c.setText(values.get(2)); 

    return theView; 
} 


public Filter geFilter() { 

    Filter filter = new Filter() {@Override 
     protected FilterResults performFiltering(CharSequence constraint) { 

      FilterResults results = new FilterResults(); 

      ArrayList al = new ArrayList(); 
      al.add("ValueA1"); 
      al.add("ValueA2"); 
      al.add("ValueA3"); 

      ArrayList bl = new ArrayList(); 
      bl.add("ValueB1"); 
      bl.add("ValueB2"); 
      bl.add("ValueB3"); 

      ArrayList < ArrayList <String>> array = new ArrayList < >(); 

      array.add(al); 
      array.add(bl); 

      results.count = array.size(); 
      results.values = array; 

      return results; 

     } 

     @Override 
     protected void publishResults(CharSequence constraint, FilterResults results) { 


      arrayList = (ArrayList) results.values; 

      notifyDataSetChanged(); 
     } 
    }; 
    return filter; 
} 

} 

В пункте выбран слушателем Прядильщиков, у меня есть:

theAdapter.getFilter().filter("Incoming"); 
+0

Вы должны пройти прямую выделенную позицию, результат фильтра будет пустым для входящих – Rahul

ответ

1

К сожалению, у вас много неприятностей с адаптером. Например, не внедряя ViewHolder paradigm. Заметьте, это не то, почему вы видите проблемы. Однако он решает проблемы производительности, которые создаст ваше решение.

Сама фильтрация не работает, потому что ArrayAdapter отслеживает собственный внутренний список данных. ArrayAdapter не гарантирует, что список, который вы отслеживаете извне, является одним и тем же. Это особенно актуально во время работы фильтра. Вы можете больше узнать об опасностях отслеживания внешнего списка, например here.

Ваш Filter очень проблематично.

  1. Он вновь присваивает внешний список данных в новый список, который не означает, что ваш arrayList больше не тот же один внутренний ArrayAdapter отслеживает. Это приведет к проблемам, возникшим позже, когда вы будете мутировать адаптер.
  2. Как бы то ни было, ваша реализация фактически не фильтрует ничего. Обычно у вас также есть второй ArrayList, чтобы отслеживать исходные данные до начала фильтрации. В противном случае невозможно восстановить данные, которые были отфильтрованы.
  3. performFiltering() имеет место на фоне нити. Пока вы не получаете доступ к arrayList во время этого метода (который был бы единственным способом фактического фильтрации данных), вам необходимо обеспечить синхронизацию всех изменений списка. ArrayAdapter сам уже обрабатывает синхронизацию, но нет возможности синхронизировать ваш внешний arrayList с ним. Это означает, что вы не можете писать фильтр без риска одновременных ошибок модификации.
  4. В publishResults(), когда results.count == 0, вы должны notifyDataSetInvalidated(). Если results.count > 0, вы должны notifyDataSetChanged().
  5. ArrayAdapter уже реализует Filterable. Вы можете добавить это к своему пользовательскому адаптеру.

Есть несколько ошибок с собственной фильтрацией ArrayAdapter.Вот a piece, в котором говорится о проблеме и о том, как ее обойти. Актуальность заключается в том, что в нем обсуждается, как создать свою собственную фильтруемую логику для устранения проблемы. Короче говоря, вы не можете создать свой собственный фильтр с помощью ArrayAdapter. Вам нужно создать свой собственный адаптер с нуля, используя вместо этого BaseAdapter.

В качестве альтернативы вы можете использовать third party library, который предоставляет очень простые средства для реализации собственной пользовательской логики фильтрации. Я настоятельно рекомендую взглянуть на этого парня. Кроме того, я настоятельно рекомендую Google больше узнать, как правильно создать пользовательский адаптер. Их много, и вам нужно научиться правильно реализовывать их с нуля.

+0

Большое спасибо за ваш ответ и указав свои ошибки –

0

Выполните следующие действия в publishResults() метода:

Очистить список, добавить результирующие данные снова и снова вызовите notifyDataSetInvalidated().

@Override 
protected void publishResults(CharSequence constraint, FilterResults results) { 

    arrayList = (ArrayList) results.values; 
    notifyDataSetChanged(); 

    clear(); 
    for(int i = 0, l = arrayList.size(); i < l; i++) { 
      add(arrayList.get(i)); 
    } 
    notifyDataSetInvalidated(); 
} 
+0

Спасибо за ваш ответ. Не могли бы вы рассказать, где я должен использовать этот кусок кода? –

+0

Проверьте обновленный ответ! –

+0

Я просто пробовал приведенный выше код, но результат тот же. Не отображать данные о событии выбора элемента spinner. –

Смежные вопросы