Building a Twitter style autocomplete for Android

I have recently been working on an android app and found myself needing a Twitter style input box that allowed certain words to be looked up using an API driven autocomplete but also supporting freetext (if you have used the compose tweet input on android, like this - free text, but if you type @ then you get a user name autocomplete).



I google'd for a while, and stumbled through a few StackOverflow answers but none of there were 100% clear, and further more, just copy-pasting the code into a dummy project I was working in didn't work. So here is a break down of the what and how this works.

There are four main components:

The XML Layout: MultiAutoCompleteTextView


This is simple - just add the MultiAutoCompleteTextView just like you would any input. The only point of interest here is the "completionThreshold" - this is just the number of characters that have to be typed before auto-complete kicks in. We have set this to one char so it kicks in early.


We then just setup the auto-complete in our Activity onCreate

SetTokeniser: UsernameTokenizer

This is a custom class that implements the Tokenizer interface. This will be used by our autocomplete imput box to work out whether or not it should be displaying a dropdown menu. If you are using a static list for lookups (countries, fixed codes from your app, etc) then this is the only thing you really need to do - then you can just set the fields ArrayAdapter as the list of Strings etc and it will automatically kick in.

In our case, we are using the @ character to identify the start of pieces of text that should be lookedup and spaces to determine the end of the look up token.


The three methods are relatively straight forward - and will drive when your app presents the drop down:
  • terminateToken(CharSequence text) - this basically just provides a presentable version of our token with a proper terminator at the end (e.g. makes sure a trailing single space in this case)
  • findTokenStart(CharSequence text, int cursor) - Just finds the position of the start of the token. It does this by iterating backwards through the provided CharSequence (the text input in the input box) starting from the position of the cursor, which is just the position of the last character edited (this means if you go back and edit text in the middle of a block it still finds the correct token).  If no valid token start is found (e.g. we go backwards and we can't find a @ character) then the current position is returned - no dropdown is displayed.
  • findTokenEnd(CharSequence text, int cursor) - As above, but finds the end position. Iterates forward until a token terminator (in our case a space) or the end of the text is found

As long as you implement these to support your token identification pattern then you will get a dropdown appearing appropriately.


Adding a text changed listener

For ease of use on this one, I have just set the activity to implement the TextWatcher interface - the reason for this is just convenience - the implementation is going to handle calling our API asyncronously, so it is easier if it has the activity context.

There are three methods that need to be implemented - four our case there will be two no-op methods and just one implementation:


The method onTextChanged is implemented - unfortunately the tokenizer will only indicate to the application when to display the dropdown - it doesn't actually call the API, so we have to slightly repeat ourselves here in handling the API invocation.  In this method we need to again check for and find the relevant valid token in the input, and if a valid token found, then pass it to our API to lookup the dataset.

To help with that, I also added some additional methods to help check for the existence of a valid token (reading them should be self explanatory, but comments included inline)


In this case, as it was just an experiment, and I didn't actually have a user lookup API I have just used the LinkedIn skills API (this code also taken in part from a StackOverflow answer).

The Async task should also be straight forward, and can be implemented in whatever pattern you are using for Async calls - but the key point to note is how we are updating our dropdown list.


The API driven, multi-autocomplete/free text field should then be working as expected



2 comments:

Coming Soon..




New mobile-first product currently underway..

0 comments:

GitHub as a CV (GaaC)

Over the recent year or so, as it has become more popular throughout the tech industry, there has been a growing amount of discussion around the idea of "GitHub as a CV" - the idea of using your online tech footprint, primarily for most people in the form of your GitHub profile, as a CV and a better representation of a potential employees ability/preference/mindset etc. There has even been a GitHub project that can automatically create a CV for you based on your profile: http://resume.github.io/ (here is mine - depressing that Coldfusion features so highly in the stats though!).  Over at NerdAbility we have really taken that idea forward (incorporating other sites like BitBucket, GoogleCode, Coursera, LinkedIn, StackOverflow, etc) and is obviously something that we think is a good idea.

But its a bad idea..

A big argument against it is that it furthers the already engrained bias towards white men. If you look at the demographic of the most active GitHub profiles there is no denying the common pattern.

I agree completely - that using GitHub as a filtering mechanism or pre-requisite for a candidate sucks. You really shouldn't do that. I have had conversations with agents where they have told me that a client only wants to see candidates who contribute to OSS, and I have declined. It doesn't qualify a candidate as being half-way competent and rules out lots of very competent people who don't have spare time to work on OSS (multiple jobs, family responsibility).


Just another data point..

I guess this is really the point here. You shouldn't rule out candidates because they don't have GitHub accounts, just like you shouldn't rule out a candidate for not having a degree etc.  I think we can all agree tech recruiting is hard, and its really hard to assess whether someone is actually a good developer and not just blagging it - so a computer scientist, I'm grateful for as much data to help with this decision as possible.

It's not that a candidate with an active GitHub profile trumps one without, but it means that its another point in an interview that we can try and use to tease out  a little bit more of an insight into the candidates skills, interests, passions.

GitHub is another point on your CV (if you are fortunate enough to have the time to setup and contribute to a GitHub profile) - just like your academic achievements and career history or anything else you choose to put on there.  If you have an interesting project it can be a talking point for an interview, in much the same way an interesting role on your CV would be.  From my point of view, I love going into interviews and hearing that the interviewer has checked out my projects on GitHub, and when the inevitable "tell us about an interesting/challenging/etc project/problem you have had" comes up, it's great to be able to talk about projects on GitHub that they have seen - not just because I know the project well, but also it will inevitably be a project that I am passionate about (otherwise I wouldn't be doing it in my spare time!).


We shouldn't be demanding OSS contributions, or set online profiles, or StackOverflow credibility - but we probably shouldn't be dismissing it as irrelevant.



0 comments: