{"id":659,"date":"2010-11-15T09:55:12","date_gmt":"2010-11-15T13:55:12","guid":{"rendered":"http:\/\/www.outofwhatbox.com\/blog\/?p=659"},"modified":"2010-11-15T19:37:32","modified_gmt":"2010-11-15T23:37:32","slug":"android-autocompletetextview-sqlite-and-dependent-fields","status":"publish","type":"post","link":"https:\/\/www.outofwhatbox.com\/blog\/2010\/11\/android-autocompletetextview-sqlite-and-dependent-fields\/","title":{"rendered":"Android: AutoCompleteTextView, SQLite, and Dependent Fields"},"content":{"rendered":"<div class=\"oowbnotice\">Update: Subclassing from SimpleCursorAdapter isn&#8217;t necessary after all. Please see <a href=\"http:\/\/www.outofwhatbox.com\/blog\/2010\/11\/android-simpler-autocompletetextview-with-simplecursoradapter\/\">my follow-up post<\/a> for a simpler way of using AutoCompleteTextView together with database queries.<\/div>\n<p>I recently integrated an <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/AutoCompleteTextView.html\">AutoCompleteTextView<\/a><\/code> into a prototype <a href=\"http:\/\/developer.android.com\/index.html\">Android<\/a> application that I&#8217;m developing. There isn&#8217;t exactly a wealth of documentation on the Web describing <code>AutoCompleteTextView<\/code>, and what I&#8217;ve found didn&#8217;t match the scenario I had in mind. Specifically:<\/p>\n<ul>\n<li>The choices came from a database, so I needed to use a <code>CursorAdapter<\/code>; and<\/li>\n<li>The <code>AutoCompleteTextView<\/code> had some dependent fields; changes to the value in the <code>AutoCompleteTextView<\/code> needed to be reflected in those dependent fields.\n<\/li>\n<\/ul>\n<p>For example, let&#8217;s use a <code>AutoCompleteTextView<\/code> for choosing states. When the user chooses a state, I want to update a <code>TextView<\/code> to show the capital of the chosen state. <\/p>\n<div class=\"oowbcaption\">\n<div class=\"oowb2col\">\n<img class=\"oowbleft2\" alt=\"AutoCompleteTextView, with no selection\" title=\"AutoCompleteTextView, with no selection\" src=\"http:\/\/img.outofwhatbox.com\/AndroidAutoText\/BeforeSelection2.png\"\/><img class=\"oowbright2\" alt=\"AutoCompleteTextView, selecting Massachusetts\" title=\"AutoCompleteTextView, selecting Massachusetts\" src=\"http:\/\/img.outofwhatbox.com\/AndroidAutoText\/ListAndAutosuggest6.png\"\/><\/div>\n<p>First the form appears with no value in the State Capital field (left); then a state is chosen from the list (right.)<\/p><\/div>\n<div class=\"oowbcaption\"><img class=\"oowbcenter\" alt=\"AutoCompleteTextView, updated with capital of Massachusetts.\" title=\"AutoCompleteTextView, updated with capital of Massachusetts.\" src=\"http:\/\/img.outofwhatbox.com\/AndroidAutoText\/AfterSelection2.png\"\/><\/p>\n<div>After a state has been chosen, its capital is also displayed.<\/div>\n<\/div>\n<h3>Adapting SQLite to <code>AutoCompleteTextView<\/code><\/h3>\n<p>The <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/AutoCompleteTextView.html\">documentation<\/a> for <code>AutoCompleteTextView<\/code> says that it obtains suggestions from a <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/BaseAdapter.html\">data adapter<\/a>. This should be familiar territory for anyone who&#8217;s used <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/ListView.html\">ListView<\/a><\/code>, which also obtains its list items from a data adapter. Not surprisingly, <code>AutoCompleteTextView<\/code> uses a <code>ListView<\/code> internally.<\/p>\n<p>However, <code>ListView<\/code> and <code>AutoCompleteTextView<\/code> require different interactions with their adapters. A standard <code>ListView<\/code> will typically need to fetch the list of items once, and only once. On the other hand, <code>AutoCompleteTextView<\/code> issues a query for matching choices whenever the user enters new text into the field. (In fact, the <code>AutoCompleteTextView<\/code> won&#8217;t issue a query <em>until<\/em> the user has typed some text. Hence the <code>CursorAdapter<\/code>&#8216;s constructor can take <code>null<\/code> for the Cursor parameter.)<\/p>\n<p><code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/SimpleCursorAdapter.html\">SimpleCursorAdapter<\/a><\/code> wasn&#8217;t designed for this kind of usage pattern; in particular, it doesn&#8217;t know how you want to query for matching choices. So, you must derive from <code>SimpleCursorAdapter<\/code>, or from its base class, <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html\">CursorAdapter<\/a><\/code>. Your subclass must supply two methods that are essentially stubbed out in <code>CursorAdapter<\/code>: <\/p>\n<ul>\n<li><code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#convertToString(android.database.Cursor)\">convertToString<\/a><\/code>, which supplies the String value that is entered into the <code>AutoCompleteTextView<\/code> when a choice is made; and<\/li>\n<li><code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#runQueryOnBackgroundThread(java.lang.CharSequence)\">runQueryOnBackgroundThread<\/a><\/code>. In this method, you invoke a query for choices that match the text entered by the user, and return a Cursor that provides the results.<\/li>\n<\/ul>\n<p>Let&#8217;s take a closer look at implementing the derived <code>CursorAdapter<\/code> class.<\/p>\n<h3><a name=\"convertToString\"><\/a><code>public CharSequence convertToString(Cursor cursor)<\/code><\/h3>\n<p>This method receives the Cursor <em>positioned to a specific row<\/em>, and returns a String label or representation <em>for that row<\/em>.<\/p>\n<div class=\"oowbbtw\">Incidentally, if you derive from <code>SimpleCursorAdapter<\/code> without overriding <code>convertToString<\/code>, the choices shown in the drop-down will look fine. However, when an item in the list is chosen, the string entered in the <code>AutoCompleteTextView<\/code> field will be gibberish like &#8220;<code><em>android.database.sqlite.SQLiteCursor@43e8b260<\/em><\/code>&#8220;.<\/p>\n<p>(This shows that <code>SimpleCursorAdapter<\/code> bypasses <code>convertToString<\/code> when building the choice list for an <code>AutoCompleteTextView<\/code>. Instead, it uses the <a href=\"#SimpleCursorAdapter\"><code>from<\/code> and <code>to<\/code> arguments in its constructor<\/a> to pull the label text directly from the database. It also demonstrates that <code>SimpleCursorAdapter<\/code> does rely on <code>convertToString<\/code> when it comes time to update the field. This inconsistency seems like a bug in <code>SimpleCursorAdapter<\/code>.)<\/p>\n<p>If you derive directly from <code>CursorAdapter<\/code> without implementing <code>convertToString<\/code>, then the behavior is consistent: you get the gibberish in the list <em>and<\/em> in the field value.<\/p>\n<p>Perhaps <code>convertToString<\/code> should have been declared <code>abstract<\/code>, since the base class implementation doesn&#8217;t seem to be very helpful.<\/div>\n<h3><a name=\"runQueryOnBackgroundThread\"><\/a><code>public Cursor runQueryOnBackgroundThread(CharSequence constraint)<\/code><\/h3>\n<p>Just to clarify, &#8220;On Background Thread&#8221; means that this method <em>is called in<\/em> a background thread \u00e2\u20ac\u201d it does <em>not<\/em> mean that you have to spawn that thread within this method.<\/p>\n<p>This method runs a query to get choices that match the input. It&#8217;s up to the application to determine what constitutes a match. (In this example, I&#8217;m searching for states whose names begin with the given letters.)<\/p>\n<p>The <code>constraint<\/code> parameter is the input that the user has typed in. It may be <code>null<\/code> if the user has typed, and then erased, input text. In this case, all results should be returned.<\/p>\n<div class=\"oowbbtw\">Note that you must not call <code>changeCursor<\/code> within this method, because <code>changeCursor<\/code> is not thread-safe. The UI will invoke <code>changeCursor<\/code> from the main thread after this method returns the new Cursor.<\/div>\n<h3>But wait, there&#8217;s more!<\/h3>\n<p>It might seem&#8230; well, simpler, to derive the new Adapter class from <code>SimpleCursorAdapter<\/code>. However, deriving from <code>CursorAdapter<\/code> requires only two additional methods to be implemented, <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#newView(android.content.Context, android.database.Cursor, android.view.ViewGroup)\">newView<\/a><\/code> and <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#bindView(android.view.View, android.content.Context, android.database.Cursor)\">bindView<\/a><\/code>, both of which are straightforward. Hence for this example, I&#8217;m using <code>CursorAdapter<\/code> as the base class. Later, I&#8217;ll <a href=\"#SimpleCursorAdapter\">describe the changes needed<\/a> to use <code>SimpleCursorAdapter<\/code> as the base.<\/p>\n<h4><a name=\"newView\"><\/a><code>public View newView(Context context, Cursor cursor, ViewGroup parent)<\/code><\/h4>\n<p><code>newView<\/code> returns a newly constructed View suitable for displaying a single item in the choice list. The usual method for doing this is to use the Inflater, which is given the resource ID of a layout that describes the new View. It&#8217;s not necessary to create your own layout file; Android provides a standard layout that&#8217;s appropriate for this purpose, identified by  <code>android.R.layout.simple_dropdown_item_1line<\/code>.<\/p>\n<div class=\"oowbbtw\">Note: Many examples of <code>newView<\/code> on the web call <code>setText<\/code> on the view before returning. This unnecessarily duplicates the code in <code>bindView<\/code>. Nor is it necessary to invoke <code>bindView<\/code> explicitly: after we return the new view, <code>bindView<\/code> will be invoked to display the value.<\/div>\n<h4><a name=\"bindView\"><\/a><code>public void bindView(View view, Context context, Cursor cursor)<\/code><\/h4>\n<p>This is called to display the label for the current row. If <code>newView<\/code> uses <code>android.R.layout.simple_dropdown_item_1line<\/code> for layout, then <code>bindView<\/code> will be called with a <code>TextView<\/code> as the <code>View<\/code> argument.<\/p>\n<h3>Updating dependent fields<\/h3>\n<p>To update dependent fields, start by creating a class that implements <code>OnItemClickListener<\/code>. (Here, it&#8217;s the Adapter class; it could also be your Activity, or some other class.) This interface defines a callback that&#8217;s invoked when the user makes a choice. The <code>setOnItemClickListener<\/code> method in <code>AutoCompleteTextView<\/code> associates the listener with the field.<\/p>\n<p>The callback method, <code>onItemClick<\/code>, receives a <code>position<\/code> parameter that identifies the row number within the result set, starting from 0. For example, if the third state, &#8220;Arizona&#8221;, is chosen, the value of<code> position<\/code> will be 2. There&#8217;s also an <code>AdapterView&lt;?><\/code> parameter, whose purpose is a bit obscure. This is the <code>ListView<\/code> belonging to the <code>AutoCompleteTextView<\/code>. (This may be the only situation in which that <code>ListView<\/code> is directly exposed to the caller.)<\/p>\n<p>We can then get the cursor from the <code>AdapterView&lt;?><\/code> parameter, and position it to the correct row, by calling <code>getItemAtPosition<\/code>. Note that <code>getItemAtPosition<\/code> returns an <code>Object<\/code>, so a cast is necessary. (It doesn&#8217;t seem to be documented anywhere that <code>listView.getItemAtPosition<\/code> will return a Cursor in this case.)<\/p>\n<p>In the full example, this logic is seen in the line:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">Cursor cursor = (Cursor) listView.getItemAtPosition(position)<\/pre>\n<p>The result would probably be the same if we replaced the above line with:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n            Cursor cursor = getCursor();\r\n            cursor.moveToPosition(position);\r\n<\/pre>\n<p>I went with the first approach because: 1) It&#8217;s (arguably) more in keeping with the Adapter&#8217;s contract. (There doesn&#8217;t seem to be any <em>guarantee<\/em> that <code>changeCursor<\/code> will be called by the main thread; without that call, <code>getCursor()<\/code> certainly won&#8217;t work.) And 2) it&#8217;s simpler, if by &#8220;simpler&#8221; we mean one less line of code.<\/p>\n<h3>The code<\/h3>\n<p>Now let&#8217;s have a look at the code. Here&#8217;s the Activity class, <code>SelectState<\/code>, with its nested Adapter class, <code>ItemAutoTextAdapter<\/code>. (The other class needed for this example, <code>AutoCompleteDbAdapter<\/code>, is available <a href=\"#AutoCompleteDbAdapter\">below<\/a>.)<\/p>\n<div class=\"oowbbtw\">ZIP files are available for the full example, using either <a href=\"http:\/\/static.outofwhatbox.com\/AndroidAutoText\/AutoCompleteExample.zip\">CursorAdapter <\/a>and <a href=\"http:\/\/static.outofwhatbox.com\/AndroidAutoText\/AutoCompleteSimpleCursor.zip\">SimpleCursorAdapter<\/a> as the base classes.<\/div>\n<pre class=\"brush: java; title: SelectState; notranslate\" title=\"SelectState\">\r\npackage org.oowb.AutoCompleteExample;\r\n\r\nimport android.app.Activity;\r\nimport android.content.Context;\r\nimport android.database.Cursor;\r\nimport android.os.Bundle;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\nimport android.widget.AdapterView;\r\nimport android.widget.AutoCompleteTextView;\r\nimport android.widget.Button;\r\nimport android.widget.CursorAdapter;\r\nimport android.widget.TextView;\r\n\r\n\/**\r\n * A simple Android Activity to demonstrate: \r\n * \r\n * 1) How to use an AutoCompleteTextView with a CursorAdapter\r\n * \r\n * 2) How to access the cursor row for the user's choice, to obtain \r\n *    additional data from that row when an item is selected.\r\n * \r\n * @author Dan Breslau\r\n * \r\n *\/\r\npublic class SelectState extends Activity {\r\n    \/**\r\n     * Specializes CursorAdapter to supply choices to a AutoCompleteTextView.\r\n     * Also implements OnItemClickListener to be notified when a choice is made,\r\n     * and uses the choice to update other fields on the Activity form.\r\n     *\/\r\n    class ItemAutoTextAdapter extends CursorAdapter\r\n            implements android.widget.AdapterView.OnItemClickListener {\r\n\r\n        private AutoCompleteDbAdapter mDbHelper;\r\n\r\n        \/**\r\n         * Constructor. Note that no cursor is needed when we create the\r\n         * adapter. Instead, cursors are created on demand when completions are\r\n         * needed for the field. (see\r\n         * {@link ItemAutoTextAdapter#runQueryOnBackgroundThread(CharSequence)}.)\r\n         * \r\n         * @param dbHelper\r\n         *            The AutoCompleteDbAdapter in use by the outer class\r\n         *            object.\r\n         *\/\r\n        public ItemAutoTextAdapter(AutoCompleteDbAdapter dbHelper) {\r\n            \/\/ Call the CursorAdapter constructor with a null Cursor.\r\n            super(SelectState.this, null);\r\n            mDbHelper = dbHelper;\r\n        }\r\n\r\n        \/**\r\n         * Invoked by the AutoCompleteTextView field to get completions for the\r\n         * current input.\r\n         * \r\n         * NOTE: If this method either throws an exception or returns null, the\r\n         * Filter class that invokes it will log an error with the traceback,\r\n         * but otherwise ignore the problem. No choice list will be displayed.\r\n         * Watch those error logs!\r\n         * \r\n         * @param constraint\r\n         *            The input entered thus far. The resulting query will\r\n         *            search for states whose name begins with this string.\r\n         * @return A Cursor that is positioned to the first row (if one exists)\r\n         *         and managed by the activity.\r\n         *\/\r\n        @Override\r\n        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {\r\n            if (getFilterQueryProvider() != null) {\r\n                return getFilterQueryProvider().runQuery(constraint);\r\n            }\r\n\r\n            Cursor cursor = mDbHelper.getMatchingStates(\r\n                    (constraint != null ? constraint.toString() : null));\r\n\r\n            return cursor;\r\n        }\r\n\r\n        \/**\r\n         * Called by the AutoCompleteTextView field to get the text that will be\r\n         * entered in the field after a choice has been made.\r\n         * \r\n         * @param Cursor\r\n         *            The cursor, positioned to a particular row in the list.\r\n         * @return A String representing the row's text value. (Note that this\r\n         *         specializes the base class return value for this method,\r\n         *         which is {@link CharSequence}.)\r\n         *\/\r\n        @Override\r\n        public String convertToString(Cursor cursor) {\r\n            final int columnIndex = cursor.getColumnIndexOrThrow(&quot;state&quot;);\r\n            final String str = cursor.getString(columnIndex);\r\n            return str;\r\n        }\r\n\r\n        \/**\r\n         * Called by the ListView for the AutoCompleteTextView field to display\r\n         * the text for a particular choice in the list.\r\n         * \r\n         * @param view\r\n         *            The TextView used by the ListView to display a particular\r\n         *            choice.\r\n         * @param context\r\n         *            The context (Activity) to which this form belongs;\r\n         *            equivalent to {@code SelectState.this}.\r\n         * @param cursor\r\n         *            The cursor for the list of choices, positioned to a\r\n         *            particular row.\r\n         *\/\r\n        @Override\r\n        public void bindView(View view, Context context, Cursor cursor) {\r\n            final String text = convertToString(cursor);\r\n            ((TextView) view).setText(text);\r\n        }\r\n\r\n        \/**\r\n         * Called by the AutoCompleteTextView field to display the text for a\r\n         * particular choice in the list.\r\n         * \r\n         * @param context\r\n         *            The context (Activity) to which this form belongs;\r\n         *            equivalent to {@code SelectState.this}.\r\n         * @param cursor\r\n         *            The cursor for the list of choices, positioned to a\r\n         *            particular row.\r\n         * @param parent\r\n         *            The ListView that contains the list of choices.\r\n         * \r\n         * @return A new View (really, a TextView) to hold a particular choice.\r\n         *\/\r\n        @Override\r\n        public View newView(Context context, Cursor cursor, ViewGroup parent) {\r\n            final LayoutInflater inflater = LayoutInflater.from(context);\r\n            final View view =\r\n                    inflater.inflate(android.R.layout.simple_dropdown_item_1line,\r\n                            parent, false);\r\n \r\n           return view;\r\n        }\r\n\r\n        \/**\r\n         * Called by the AutoCompleteTextView field when a choice has been made\r\n         * by the user.\r\n         * \r\n         * @param listView\r\n         *            The ListView containing the choices that were displayed to\r\n         *            the user.\r\n         * @param view\r\n         *            The field representing the selected choice\r\n         * @param position\r\n         *            The position of the choice within the list (0-based)\r\n         * @param id\r\n         *            The id of the row that was chosen (as provided by the _id\r\n         *            column in the cursor.)\r\n         *\/\r\n        @Override\r\n        public void onItemClick(AdapterView&lt;?&gt; listView, View view, int position, long id) {\r\n            \/\/ Get the cursor, positioned to the corresponding row in the result set\r\n            Cursor cursor = (Cursor) listView.getItemAtPosition(position);\r\n\r\n            \/\/ Get the state's capital from this row in the database.\r\n            String capital = cursor.getString(cursor.getColumnIndexOrThrow(&quot;capital&quot;));\r\n\r\n            \/\/ Update the parent class's TextView\r\n            mStateCapitalView.setText(capital);\r\n        }\r\n    }\r\n\r\n    private TextView mStateCapitalView;\r\n    private AutoCompleteTextView mStateNameView;\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        AutoCompleteDbAdapter dbHelper = new AutoCompleteDbAdapter(this);\r\n        setContentView(R.layout.selectstate);\r\n        Button confirmButton = (Button) findViewById(R.id.confirm);\r\n        confirmButton.setOnClickListener(new View.OnClickListener() {\r\n            public void onClick(View view) {\r\n                setResult(RESULT_OK);\r\n                finish();\r\n            }\r\n        });\r\n\r\n        mStateCapitalView = (TextView) findViewById(R.id.state_capital);\r\n        mStateNameView = (AutoCompleteTextView) findViewById(R.id.state_name);\r\n\r\n        \/\/ Create an ItemAutoTextAdapter for the State Name field,\r\n        \/\/ and set it as the OnItemClickListener for that field.\r\n        ItemAutoTextAdapter adapter = this.new ItemAutoTextAdapter(dbHelper);\r\n        mStateNameView.setAdapter(adapter);\r\n        mStateNameView.setOnItemClickListener(adapter);\r\n    }\r\n}\r\n<\/pre>\n<p><a name=\"AutoCompleteDbAdapter\"><\/a><br \/>\nHere&#8217;s the <code>AutoCompleteDbAdapter<\/code> class.  It&#8217;s less interesting for this example, so the code is hidden by default. Click on the &#8220;show source&#8221; link to view it.<\/p>\n<pre class=\"brush: java; collapse: true; light: false; title: AutoCompleteDbAdapter; toolbar: true; notranslate\" title=\"AutoCompleteDbAdapter\">\r\npackage org.oowb.AutoCompleteExample;\r\n\r\nimport android.app.Activity;\r\nimport android.content.ContentValues;\r\nimport android.content.Context;\r\nimport android.database.Cursor;\r\nimport android.database.SQLException;\r\nimport android.database.sqlite.SQLiteDatabase;\r\nimport android.database.sqlite.SQLiteOpenHelper;\r\nimport android.util.Log;\r\n\r\n\/**\r\n * Simple database access helper class.\r\n * \r\n * @author Dan Breslau\r\n *\/\r\npublic class AutoCompleteDbAdapter {\r\n    \/**\r\n     * List of states and capitals.\r\n     *\/\r\n    private static final String[][] States = {\r\n            { &quot;Alabama&quot;, &quot;Montgomery&quot; },\r\n            { &quot;Alaska&quot;, &quot;Juneau&quot; },\r\n            { &quot;Arizona&quot;, &quot;Phoenix&quot; },\r\n            { &quot;Arkansas&quot;, &quot;Little Rock&quot; },\r\n            { &quot;California&quot;, &quot;Sacramento&quot; },\r\n            { &quot;Colorado&quot;, &quot;Denver&quot; },\r\n            { &quot;Confusion&quot;, &quot;\\&quot;C\\&quot;&quot; },\r\n            { &quot;Connecticut&quot;, &quot;Hartford&quot; },\r\n            { &quot;Delaware&quot;, &quot;Dover&quot; },\r\n            { &quot;Florida&quot;, &quot;Tallahassee&quot; },\r\n            { &quot;Georgia&quot;, &quot;Atlanta&quot; },\r\n            { &quot;Hawaii&quot;, &quot;Honolulu&quot; },\r\n            { &quot;Idaho&quot;, &quot;Boise&quot; },\r\n            { &quot;Illinois&quot;, &quot;Springfield&quot; },\r\n            { &quot;Indiana&quot;, &quot;Indianapolis&quot; },\r\n            { &quot;Iowa&quot;, &quot;Des Moines&quot; },\r\n            { &quot;Kansas&quot;, &quot;Topeka&quot; },\r\n            { &quot;Kentucky&quot;, &quot;Frankfort&quot; },\r\n            { &quot;Louisiana&quot;, &quot;Baton Rouge&quot; },\r\n            { &quot;Maine&quot;, &quot;Augusta&quot; },\r\n            { &quot;Maryland&quot;, &quot;Annapolis&quot; },\r\n            { &quot;Massachusetts&quot;, &quot;Boston&quot; },\r\n            { &quot;Michigan&quot;, &quot;Lansing&quot; },\r\n            { &quot;Minnesota&quot;, &quot;St. Paul&quot; },\r\n            { &quot;Mississippi&quot;, &quot;Jackson&quot; },\r\n            { &quot;Missouri&quot;, &quot;Jefferson City&quot; },\r\n            { &quot;Montana&quot;, &quot;Helena&quot; },\r\n            { &quot;Nebraska&quot;, &quot;Lincoln&quot; },\r\n            { &quot;Nevada&quot;, &quot;Carson City&quot; },\r\n            { &quot;New Hampshire&quot;, &quot;Concord&quot; },\r\n            { &quot;New Jersey&quot;, &quot;Trenton&quot; },\r\n            { &quot;New Mexico&quot;, &quot;Santa Fe&quot; },\r\n            { &quot;New York&quot;, &quot;Albany&quot; },\r\n            { &quot;North Carolina&quot;, &quot;Raleigh&quot; },\r\n            { &quot;North Dakota&quot;, &quot;Bismarck&quot; },\r\n            { &quot;Ohio&quot;, &quot;Columbus&quot; },\r\n            { &quot;Oklahoma&quot;, &quot;Oklahoma City&quot; },\r\n            { &quot;Oregon&quot;, &quot;Salem&quot; },\r\n            { &quot;Pennsylvania&quot;, &quot;Harrisburg&quot; },\r\n            { &quot;Rhode Island&quot;, &quot;Providence&quot; },\r\n            { &quot;South Carolina&quot;, &quot;Columbia&quot; },\r\n            { &quot;South Dakota&quot;, &quot;Pierre&quot; },\r\n            { &quot;Tennessee&quot;, &quot;Nashville&quot; },\r\n            { &quot;Texas&quot;, &quot;Austin&quot; },\r\n            { &quot;Utah&quot;, &quot;Salt Lake City&quot; },\r\n            { &quot;Vermont&quot;, &quot;Montpelier&quot; },\r\n            { &quot;Virginia&quot;, &quot;Richmond&quot; },\r\n            { &quot;Washington&quot;, &quot;Olympia&quot; },\r\n            { &quot;West Virginia&quot;, &quot;Charleston&quot; },\r\n            { &quot;Wisconsin&quot;, &quot;Madison&quot; },\r\n            { &quot;Wyoming&quot;, &quot;Cheyenne&quot; }\r\n    };\r\n\r\n    private static final String DATABASE_NAME = &quot;capitals&quot;;\r\n    private static final String TABLE_NAME = &quot;state&quot;;\r\n    private static final int DATABASE_VERSION = 1;\r\n\r\n    private class DatabaseHelper extends SQLiteOpenHelper {\r\n\r\n        DatabaseHelper(Context context) {\r\n            super(context, DATABASE_NAME, null, DATABASE_VERSION);\r\n        }\r\n\r\n        @Override\r\n        public void onCreate(SQLiteDatabase db) {\r\n            final String DATABASE_CREATE_STATES =\r\n                    &quot;create table &quot; + TABLE_NAME\r\n                            + &quot;(_id integer primary key autoincrement&quot;\r\n                            + &quot;, state text not null&quot;\r\n                            + &quot;, capital text not null)&quot;;\r\n\r\n            db.execSQL(DATABASE_CREATE_STATES);\r\n            populateWithData(db);\r\n        }\r\n\r\n        @Override\r\n        public void onUpgrade(SQLiteDatabase db, int old, int new) {\r\n            db.execSQL(&quot;DROP TABLE IF EXISTS &quot; + TABLE_NAME);\r\n            onCreate(db);\r\n        }\r\n    }\r\n\r\n    private DatabaseHelper mDbHelper;\r\n    private SQLiteDatabase mDb;\r\n    private final Activity mActivity;\r\n\r\n    \/**\r\n     * Constructor - takes the context to allow the database to be\r\n     * opened\/created\r\n     * \r\n     * @param activity\r\n     *            the Activity that is using the database\r\n     *\/\r\n    public AutoCompleteDbAdapter(Activity activity) {\r\n        this.mActivity = activity;\r\n        mDbHelper = this.new DatabaseHelper(activity);\r\n        mDb = mDbHelper.getWritableDatabase();\r\n    }\r\n\r\n    \/**\r\n     * Closes the database.\r\n     *\/\r\n    public void close() {\r\n        mDbHelper.close();\r\n    }\r\n\r\n    \/**\r\n     * Return a Cursor that returns all states (and their state capitals) where\r\n     * the state name begins with the given constraint string.\r\n     * \r\n     * @param constraint\r\n     *            Specifies the first letters of the states to be listed. If\r\n     *            null, all rows are returned.\r\n     * @return Cursor managed and positioned to the first state, if found\r\n     * @throws SQLException\r\n     *             if query fails\r\n     *\/\r\n    public Cursor getMatchingStates(String constraint) throws SQLException {\r\n\r\n        String queryString =\r\n                &quot;SELECT _id, state, capital FROM &quot; + TABLE_NAME;\r\n\r\n        if (constraint != null) {\r\n            \/\/ Query for any rows where the state name begins with the\r\n            \/\/ string specified in constraint.\r\n            \/\/\r\n            \/\/ NOTE:\r\n            \/\/ If wildcards are to be used in a rawQuery, they must appear\r\n            \/\/ in the query parameters, and not in the query string proper.\r\n            \/\/ See http:\/\/code.google.com\/p\/android\/issues\/detail?id=3153\r\n            constraint = constraint.trim() + &quot;%&quot;;\r\n            queryString += &quot; WHERE state LIKE ?&quot;;\r\n        }\r\n        String params[] = { constraint };\r\n\r\n        if (constraint == null) {\r\n            \/\/ If no parameters are used in the query,\r\n            \/\/ the params arg must be null.\r\n            params = null;\r\n        }\r\n        try {\r\n            Cursor cursor = mDb.rawQuery(queryString, params);\r\n            if (cursor != null) {\r\n                this.mActivity.startManagingCursor(cursor);\r\n                cursor.moveToFirst();\r\n                return cursor;\r\n            }\r\n        }\r\n        catch (SQLException e) {\r\n            Log.e(&quot;AutoCompleteDbAdapter&quot;, e.toString());\r\n            throw e;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    \/**\r\n     * Populates the database with data on states and state capitals.\r\n     * \r\n     * @param db\r\n     *            The database to be populated; must have the appropriate table\r\n     *            (&quot;state&quot;) and columns (&quot;state&quot; and &quot;values&quot;) already set up.\r\n     *\/\r\n    private void populateWithData(SQLiteDatabase db) {\r\n        try {\r\n            db.beginTransaction();\r\n            ContentValues values = new ContentValues();\r\n            \/\/ Populate the database with the state\/capital city\r\n            \/\/ pairs found in the States array.\r\n            for (String[] s : States) {\r\n                values.put(&quot;state&quot;, s[0]);\r\n                values.put(&quot;capital&quot;, s[1]);\r\n\r\n                db.insert(TABLE_NAME, &quot;state&quot;, values);\r\n            }\r\n            db.setTransactionSuccessful();\r\n        }\r\n        finally {\r\n            db.endTransaction();\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<h3><a name=\"SimpleCursorAdapter\"><\/a>Using <code>SimpleCursorAdapter<\/code><\/h3>\n<p>As mentioned above, changing the Adapter&#8217;s base class to <code>SimpleCursorAdapter<\/code> is fairly simple. Here&#8217;s a summary of the changes needed:<\/p>\n<ul>\n<li>The <code>SimpleCursorAdapter<\/code> constructor requires a resource ID for the layout used for items in the list. As before, we are using <code>android.R.layout.simple_dropdown_item_1line<\/code> for this layout.\n<\/li>\n<li>The constructor for <code>SimpleCursorAdapter<\/code> also requires parameters named <code>from<\/code> and <code>to<\/code>. These are arrays indicating which column(s) in the database hold the relevant data, and which field(s) in the View will display that data.<\/li>\n<div>When the <code>SimpleCursorAdapter<\/code> is used to support an <code>AutoCompleteTextView<\/code>, only one column\/field pair is used. The column, of course, is the column that supplies the names (here, &#8220;state&#8221;.) But how do we identify the field in the <code>to<\/code> array? Help comes to us through <code>android.R.id.text1<\/code>, a resource that is used to identify the first (and only) TextField within the standard item layout (<code>android.R.layout.simple_dropdown_item_1line<\/code>.)<\/div>\n<div>This results in the following definitions for the <code>from<\/code> and <code>to<\/code> parameters. (I defined these in the outer <code>SelectState<\/code> class, because an inner class isn&#8217;t allowed to have static data.)<\/div>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n    final static int[] to = new int[] { android.R.id.text1 };\r\n    final static String[] from = new String[] { &quot;state&quot; };\r\n<\/pre>\n<li>The constructor is changed to call its superclass as follows:<\/li>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nsuper(SelectState.this, \r\n        android.R.layout.simple_dropdown_item_1line, \r\n        null, from, to);\r\n<\/pre>\n<li>The <code>newView<\/code> and <code>bindView<\/code> methods can be removed.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>There isn\u00e2\u20ac\u2122t a wealth of documentation on the Web describing AutoCompleteTextView, especially for using it with a CursorAdapter. Here&#8217;s a summary of my own experience implementing with this combination of classes.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[33,3],"tags":[51,34,35,36],"_links":{"self":[{"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts\/659"}],"collection":[{"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/comments?post=659"}],"version-history":[{"count":4,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts\/659\/revisions"}],"predecessor-version":[{"id":669,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts\/659\/revisions\/669"}],"wp:attachment":[{"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/media?parent=659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/categories?post=659"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/tags?post=659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}