martin
martin

Reputation: 1139

ListActvity filter for custom ArrayAdapter

I've read several tutorials about the use of a simple filter for a ListActivity but I just can't figure out why it doesn't work for me. The TextWatcher's onTextChanged() method is executed with the correct string to be searched for....but then nothing happens. I think the problem might be the custom adapter but how can I make it work?

Maybe you could have a look at it :) Thanks!

package com.RemoteControl;

import com.RemoteControl.R;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

public class RemoteControlPlaylist extends ListActivity {

    static Handler error_class_Handler;
    static Handler viewHandler;
    static EfficientAdapter adapter = null;
    private static EditText filterText = null;


    static class EfficientAdapter extends ArrayAdapter<String> {

        public EfficientAdapter(Context context, int textViewResourceId, int playlistTitle, String[] objects) {
            super(context, textViewResourceId, playlistTitle, objects);

            mInflater = LayoutInflater.from(context);
        }

        private LayoutInflater mInflater;

        @Override
        public int getCount() {
            return Settings.playlistlength;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder holder;

            if (convertView == null) 
            {
                holder = new ViewHolder();

                convertView = mInflater.inflate(R.layout.listview, null);

                holder.text = (TextView) convertView.findViewById(R.string.playlist_title);
                holder.image = (ImageView) convertView.findViewById(R.string.playlist_play);
                holder.queue = (TextView) convertView.findViewById(R.string.playlist_queue);

                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }


            return convertView;
        }


        static class ViewHolder {
            TextView text, queue;
            ImageView image;
        }

        @Override
        public String getItem(int position) {
            return Settings.playlist[position];
        }
    }

    private static TextWatcher filterTextWatcher = new TextWatcher() {

        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }


        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            adapter.getFilter().filter(s);
        }

    };



    void initialize()
    {
        adapter = new EfficientAdapter(this, R.layout.listview, R.string.playlist_title, Settings.playlist);
        setListAdapter(adapter);

        filterText = (EditText) findViewById(R.string.search_box);
        filterText.addTextChangedListener(filterTextWatcher);
    }



    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.playlist);

        getListView().setTextFilterEnabled(true);

        initialize();

        error_class_Handler = new Handler();
        viewHandler = new Handler();

        getListView().setFastScrollEnabled(true);

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        filterText.removeTextChangedListener(filterTextWatcher);
    }

}

where the playlist.xml file is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >

    <EditText android:id="@+string/search_box" 
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:hint="type to filter"
       android:inputType="text"
       android:maxLines="1"/>

    <ListView android:id="@+android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"/>

</LinearLayout>

and every row within the ListView is a listview.xml element:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


     <TextView
            android:id="@+string/playlist_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            <!-- some layout stuff --> />

    <ImageView 
        android:id="@+string/playlist_play"
        android:src="@drawable/playlist_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
            <!-- some layout stuff --> />

    <TextView
        android:id="@+string/playlist_queue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
            <!-- some layout stuff --> />


</RelativeLayout>

Upvotes: 4

Views: 3087

Answers (2)

Vinay W
Vinay W

Reputation: 10190

Read the source code of ArrayFilter in ArrayAdapter class to learn from the way the developers of Android tackle this problem.

The classArrayFilter is a custom Filter class, whose instance is used and returned by the getFilter method. I'm sure you will have all your answers if you go through it.

Upvotes: 0

Mikita Belahlazau
Mikita Belahlazau

Reputation: 15434

I think standard filter from array adapter filters only those List(array) of objects, which you pass it in constructor. But you override methods getCount getItem and etc, so adapter doesn't use list you passed in constructor. But when you call getFilter().filter(s) it filters this list.

So you have class EfficientAdapter, it extends ArrayAdapter. When you create EfficientAdapter - ArrayAdapter's part created and initialized too. In constructor you passed array of strings and ArrayAdapter's part stores them. Standard filter will filter them instead of your Settings.playlist list. What you can do - not to use Settings.playlist (and not override getItem...), but use only list you passed in constructor. I think then it should work.

Internally ArrayAdapter has following fields:

/**
 * Contains the list of objects that represent the data of this ArrayAdapter.
 * The content of this list is referred to as "the array" in the documentation.
 */
private List<T> mObjects;

private ArrayList<T> mOriginalValues;

Internal ArrayAdapter's filter -ArrayFilter, filters mOriginalValues and add all values, that matches keeps in mObjects, and then ArrayAdapter 'shows' mObjects.

See source code of ArrayAdapter (and ArrayFilter) to better undestand what getFilter().filter(s) does in your case.

Upvotes: 5

Related Questions