6

This is a follow up to my question earlier here: Android: Autocomplete TextView Similar To The Facebook App.

The Background:

My requirement in the question (link posted above) was to have an AutoCompleteTextView similar to the one used in the Facebook app and several others too. The solution was to use a multi-line MultiAutoCompleteTextView The idea was to enable users to type their Friends names directly while creating a Status Update. The solution in the answer works fine from a standalone point of view. However, when I stared integrating the solution in my existing code, it still works with the correct drop-down et all. I see the filtered list of my friends thanks to a solution from here: https://stackoverflow.com/a/12363961/1350013. I use a custom ListView with a BaseAdapter instead of the GridView from the solution.

The Problem:

My code makes use of a BaseAdapter which implements Filterable. As mentioned above, works fine.

When I select a Friend from the filtered list, is where the problem is. The MultiAutoCompleteTextView, after selection, displays this: @MY_PACKAGE_NAME.Friends.getFriends@406c1058 instead of the Friend's name. What would I have to change to show the Name instead of the garbled text? If it helps, the Class I run this in extends a SherlockActivity and not a SherlockListActivity.

Now I am not sure what the relevant code would be to find out where the problem might lie, so I will post as much relevant code as possible. I am a noob, so please be easy and ask for any additional code. I will promptly comply. Likewise, if something here is not needed is cluttering the post, I will remove that.

CODE BLOCKS

The Tokenizer from the solution from my earlier question. Linked at the top (In the onCreate() method)

editStatusUpdate = (MultiAutoCompleteTextView) findViewById(R.id.editStatusUpdate);
editStatusUpdate.addTextChangedListener(filterTextWatcher);

editStatusUpdate.setTokenizer(new Tokenizer() {

    @Override
    public CharSequence terminateToken(CharSequence text) {

        int i = text.length();

        while (i > 0 && text.charAt(i - 1) == ' ') {
            i--;
        }

        if (i > 0 && text.charAt(i - 1) == ' ') {
            return text;
        } else {
            if (text instanceof Spanned) {
                SpannableString sp = new SpannableString(text + " ");
                TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
                return sp;
            } else {
                return text.toString() + " ";
            }
        }
    }

    @Override
    public int findTokenStart(CharSequence text, int cursor) {

        int i = cursor;

        while (i > 0 && text.charAt(i - 1) != '@') {
            i--;
        }

        if (i < 1 || text.charAt(i - 1) != '@') {
            return cursor;
        }

        return i;
    }

    @Override
    public int findTokenEnd(CharSequence text, int cursor) {

        int i = cursor;
        int len = text.length();

        while (i < len) {
            if (text.charAt(i) == ' ') {
                return i;
            } else {
                i++;
            }
        }

        return len;

    }
});

The TextWatcher, also from the solution to the earlier question:

private TextWatcher filterTextWatcher = new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

        Layout layout = editStatusUpdate.getLayout();
        int pos = editStatusUpdate.getSelectionStart();
        int line = layout.getLineForOffset(pos);
        int baseline = layout.getLineBaseline(line);

        int bottom = editStatusUpdate.getHeight();

        editStatusUpdate.setDropDownVerticalOffset(baseline - bottom);

    }

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

    }

    @Override
    public void afterTextChanged(Editable s) {

    }
};

For my ArrayList:

public class getFriends {

    String friendID;
    String friendName;
    String friendProfile;

    boolean selected;

    // SET FRIENDS ID
    public void setFriendID(String friendID) {
        this.friendID = friendID;
    }

    // GET FRIENDS ID
    public String getFriendID() {
        return friendID;
    }

    // SET FRIENDS NAME
    public void setFriendName(String friendName) {
        this.friendName = friendName;
    }

    // GET FRIENDS NAME
    public String getFriendName() {
        return friendName;
    }

    // SET FRIENDS PROFILE
    public void setFriendProfile(String friendProfile) {
        this.friendProfile = friendProfile;
    }

    // GET FRIENDS PROFILE
    public String getFriendProfile() {
        return friendProfile;
    }
}
Community
  • 1
  • 1
Siddharth Lele
  • 27,623
  • 15
  • 98
  • 151
  • I haven't looked through the other question's code but it seems that the method `toString` is getting called for your `getFriends` class(horrible naming by the way). Try to add an overrided `toString` method to the `getFriends` class, something like this: `@Override public String toString() {return friendName;}` and see what happens. – user Oct 20 '12 at 13:08
  • First. The solution in the comment worked right away. So please add this as an answer and I will accept it (with the set bounty) :-). Second. What would be a better way to name the class? When you say horrible, does it raise any concerns for the app malfunctioning? Or is it just bad naming practice? – Siddharth Lele Oct 20 '12 at 15:44
  • 1
    I've exaggerated using "horrible", there is no problem with the app functioning properly it's just that you should use the java conventions(capital letter for class name). Also, maybe the `getFriends` isn't such a good option, for example when I first read your question `getFriends` seemed more like a method name and not a class. As your class it's a data holder a name like `FriendData` or `FriendInformation` might have been a more expressive name for someone reading your code. This isn't something crucial but if you have other persons reading it you would help them understand the code. – user Oct 20 '12 at 16:43
  • @Luksprog: Thanks for the tip. Almost all similar classes in my app have these names and I will change them immediately. And again, thanks for the solution and the tip too. :-) – Siddharth Lele Oct 21 '12 at 04:48

2 Answers2

14

You should override convertResultToString(Object resultValue) in your filter, where Object is your class. This makes it possible to create a custom string for you class without relying on overriding the to String method.

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Heinrisch
  • 5,835
  • 4
  • 33
  • 43
  • 2
    this should be the accepted answer. It works better with internationalisation as you dont need to get the application context in your model object. – alaeri Jul 05 '13 at 13:30
6

Judging by the output you get it appears that your code calls the toString method on your getClass objects to retrieve the data it needs. As you want the friend's name you should implement your own toString method(by overriding it) like this:

@Override
public String toString() {
    return friendName; 
}
user
  • 86,916
  • 18
  • 197
  • 190
  • 1
    This is not how it should be done (and I would even say that it is wrong), there are designated methods for this conversion. You should not rely on the functions toString method. – Heinrisch Nov 09 '12 at 11:27