Android: Simpler AutoCompleteTextView with SimpleCursorAdapter

Sometimes it seems like nothing brings enlightenment as swiftly as publishing the results of one’s own confusion.

Earlier today, I published a lengthy examination of the work needed to supply an AutoCompleteTextView with data using a CursorAdapter. My intentions were pure, but my code was not. Where I’d seen a need for subclassing, it was because I hadn’t caught on to some of the handler methods provided by the SimpleCursorAdapter class.

Specifically, if we’re using a SimpleCursorAdapter, then:

This allows a significant refactoring of the SelectState class. Instead of the subclassed Adapter class, I’m now using anonymous inner classes to provide the cursor-to-name conversion and the filter query. The inner classes use essentially the same code as the methods that they’ve replaced.

The re-written SelectState follows. The full example can be downloaded as a ZIP file.

(See the earlier post for a description of the sample application’s functionality.)

package org.oowb.AutoCompleteExample;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.FilterQueryProvider;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.SimpleCursorAdapter.CursorToStringConverter;

/**
 * A simple Android Activity to demonstrate:
 * 
 * 1) How to use an AutoCompleteTextView with a SimpleCursorAdapter
 * 
 * 2) How to access the cursor row for the user's choice, to obtain additional
 * data from that row when an item is selected.
 * 
 * @author Dan Breslau
 * 
 */
public class SelectState extends Activity {

    final static int[] to = new int[] { android.R.id.text1 };
    final static String[] from = new String[] { "state" };

    private TextView mStateCapitalView;
    private AutoCompleteTextView mStateNameView;
    private AutoCompleteDbAdapter mDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDbHelper = new AutoCompleteDbAdapter(this);
        setContentView(R.layout.selectstate);
        Button confirmButton = (Button) findViewById(R.id.confirm);
        confirmButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                setResult(RESULT_OK);
                finish();
            }
        });

        mStateCapitalView = (TextView) findViewById(R.id.state_capital);
        mStateNameView = (AutoCompleteTextView) findViewById(R.id.state_name);

        // Create a SimpleCursorAdapter for the State Name field.
        SimpleCursorAdapter adapter = 
            new SimpleCursorAdapter(this, 
                    android.R.layout.simple_dropdown_item_1line, null,
                    from, to);
        mStateNameView.setAdapter(adapter);

        // Set an OnItemClickListener, to update dependent fields when
        // a choice is made in the AutoCompleteTextView.
        mStateNameView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> listView, View view,
                        int position, long id) {
                // Get the cursor, positioned to the corresponding row in the
                // result set
                Cursor cursor = (Cursor) listView.getItemAtPosition(position);

                // Get the state's capital from this row in the database.
                String capital = 
                    cursor.getString(cursor.getColumnIndexOrThrow("capital"));

                // Update the parent class's TextView
                mStateCapitalView.setText(capital);
            }
        });

        // Set the CursorToStringConverter, to provide the labels for the
        // choices to be displayed in the AutoCompleteTextView.
        adapter.setCursorToStringConverter(new CursorToStringConverter() {
            public String convertToString(android.database.Cursor cursor) {
                // Get the label for this row out of the "state" column
                final int columnIndex = cursor.getColumnIndexOrThrow("state");
                final String str = cursor.getString(columnIndex);
                return str;
            }
        });

        // Set the FilterQueryProvider, to run queries for choices
        // that match the specified input.
        adapter.setFilterQueryProvider(new FilterQueryProvider() {
            public Cursor runQuery(CharSequence constraint) {
                // Search for states whose names begin with the specified letters.
                Cursor cursor = mDbHelper.getMatchingStates(
                        (constraint != null ? constraint.toString() : null));
                return cursor;
            }
        });
    }
}
, , ,

13 Comments

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>