1

I have an EditText control on top of a ListView control in my layout. This layout is loaded into a Fragment derived class. I have also associated a TextWatcher interface with the EditText control so that each time text is entered into the EditText, the ListView filters the data based on the input text. The ListView's adapter implements Filterable behaviour by overriding GetFilter. The Fragment class that I am describing is part of a FragmentTabHost control which in turn loads 3 tabs at runtime.

Filtering the list based on what I enter in the EditText control works correctly. The issue I am facing is that when I click on some other Tab and then come back to my Tab which has this EditText with a TextWatcher, it is not clearing the previously entered text. I also notice that the filtered list is now empty. Once I manually remove the previous text from the EditText, the List re-appears with the old data.

Please let me know how to reset the filter and clear the text in the EditText control when I tab out of the current fragment. Basically I do not want the EditText control and the Filter to retain the old context each time I click on the Fragment. I have pasted sections of the code from the Fragment and List Adapter.

Thanks Balaji

public class Favourites extends Fragment implements LoaderCallbacks<Cursor> {

ListView listView1;
ArrayList<FavouriteSearchResults> searchResults;
FavouritesBaseAdapter customAdapter;
private ProgressBar progressBar;
private EditText editText;

final int MENU_MAKE_CALL = 100;
final int MENU_SEND_MESSAGE = 101;
final int MENU_SEND_DIAL = 102;
final int MENU_COPY_CLIP = 103;
final int MENU_SEND_NUMBER = 104;
final int MENU_VIEW_CONTACT = 105;

private static final int LIST_ID = 1004;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.setHasOptionsMenu(true); //Call this so that onCreateOptionsMenu is called
}

private class MyFocusChangeListener implements OnFocusChangeListener {

    Context mContext;
    public MyFocusChangeListener(Context context) {
        mContext = context;
    }
    public void onFocusChange(View v, boolean hasFocus){

        if(v.getId() == R.id.txtSearch && !hasFocus) {

            InputMethodManager imm =  (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

        }
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.favourites, container, false);

    editText = (EditText) v.findViewById(R.id.txtSearch);

    OnFocusChangeListener ofcListener = new MyFocusChangeListener(getActivity());
    editText.setOnFocusChangeListener(ofcListener);

    editText.addTextChangedListener(new TextWatcher() {

        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text
            customAdapter.getFilter().filter(cs);
        }

        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub

        }

        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub
        }
    }); 


@Override
public Filter getFilter() {
    // TODO Auto-generated method stub

    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {

            FilterResults results = new FilterResults();

            if(charSequence == null || charSequence.length() == 0) {
                results.values = searchArrayList; //Return original list if search is cleared
                results.count = searchArrayList.size();
            }
            else {
                ArrayList<FavouriteSearchResults> tempResults = new ArrayList<FavouriteSearchResults>();
                for(int i = 0;i < searchArrayList.size();i++) {
                    FavouriteSearchResults favResults = searchArrayList.get(i);

                    String sContactName = favResults.GetName();
                    String sId = favResults.GetId();

                    String searchChar = charSequence.toString();

                    if (sContactName.toLowerCase().contains(searchChar.toLowerCase())) {
                        FavouriteSearchResults newFavResults = new FavouriteSearchResults(sContactName);
                        newFavResults.SetId(sId);

                        tempResults.add(newFavResults);
                    }
                }

                results.values = tempResults;
                results.count = tempResults.size();
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            //Set the filtered list into our copy list
            searchFilteredArrayList = (ArrayList<FavouriteSearchResults>)filterResults.values;
            notifyDataSetChanged();
        }
    };
user3140417
  • 83
  • 2
  • 7

1 Answers1

2

First of all, I would point out that your getFilter() method is extremely not efficient. It creates new Filter every time user types/deletes a letter. This is quite stressful for the garbage collector. Instead, I would suggest creating Filter instance in your fragment and return this instance in getFilter() method.

Also, if you really want to clear edit text and reset filter - I would override onDestroyView method in your fragment implementation and do that stuff there.

@Override
public void onDestroyView() {
    editText.setText("");
    editText.setOnFocusChangeListener(null);
    super.onDestroyView();
}

Also as you might know, anonymous classes indirectly store reference to the parent class, so just to be safe and avoid weird circular dependencies preventing your fragment of being GCed, I would suggest declaring your anonymous classes (TextWatcher and Filter) as public static classes:

public static class MyTextWatcher implements TextWatcher
{
     public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text

            //you might need to pass this adapter as a constructor parameter
            customAdapter.getFilter().filter(cs);
        }

        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub

        }

        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub
        }
}

public static class MyFilter extends Filter
{

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        //you implementation
    }

    @Override
    protected void publishResults(CharSequence constraint,
            FilterResults results) {
        //you implementation
    }
}

And then just instantiate those instances:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    .......

    editText.addTextChangedListener(new MyTextWatcher());
    .......
}

and

@Override
public Filter getFilter() {
    if(filter == null)
    {
        filter = new MyFilter();
    }
    return filter;
}

Also, I've seen some memory leak issues related to EditText views. You might consider checking this post

Community
  • 1
  • 1
Pavel Dudka
  • 20,754
  • 7
  • 70
  • 83
  • Thanks a lot for the tip Pavel. I will rewrite the code and get back to you with any questions I may have. Balaji. – user3140417 Dec 28 '13 at 08:41
  • Code to reset the text of the EditText control does not work from the onDestroyView event. It works only from the onResume event. This is based on the article from this link: – user3140417 Dec 28 '13 at 09:25
  • Missed the link: http://stackoverflow.com/questions/13303469/edittext-settext-not-working-with-fragment – user3140417 Dec 28 '13 at 09:26