{"id":663,"date":"2010-11-15T19:33:57","date_gmt":"2010-11-15T23:33:57","guid":{"rendered":"http:\/\/www.outofwhatbox.com\/blog\/?p=663"},"modified":"2010-11-15T19:33:57","modified_gmt":"2010-11-15T23:33:57","slug":"android-simpler-autocompletetextview-with-simplecursoradapter","status":"publish","type":"post","link":"https:\/\/www.outofwhatbox.com\/blog\/2010\/11\/android-simpler-autocompletetextview-with-simplecursoradapter\/","title":{"rendered":"Android: Simpler AutoCompleteTextView with SimpleCursorAdapter"},"content":{"rendered":"<p>Sometimes it seems like nothing brings enlightenment as swiftly as publishing the results of one&#8217;s own confusion.<\/p>\n<p>Earlier today, I published a <a href=\"http:\/\/www.outofwhatbox.com\/blog\/2010\/11\/android-autocompletetextview-sqlite-and-dependent-fields\/\">lengthy examination<\/a> of the work needed to supply an <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/AutoCompleteTextView.html\">AutoCompleteTextView<\/a> with data using a <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html\">CursorAdapter<\/a>. My intentions were pure, but my code was not. Where I&#8217;d seen a need for subclassing, it was because I hadn&#8217;t caught on to some of the handler methods provided by the <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/SimpleCursorAdapter.html\"><code>SimpleCursorAdapter<\/code><\/a> class.<\/p>\n<p>Specifically, if we&#8217;re using a SimpleCursorAdapter, then:<\/p>\n<ul>\n<li>We don&#8217;t need to override the <code><a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#convertToString(android.database.Cursor)\">convertToString<\/a><\/code> method, if instead we call <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/SimpleCursorAdapter.html#setCursorToStringConverter%28android.widget.SimpleCursorAdapter.CursorToStringConverter%29\"><code>adapter.setCursorToStringConverter<\/code><\/a>.<\/li>\n<li>And there&#8217;s no need to override <code>runQueryOnBackgroundThread<\/code>, if instead we call <a href=\"http:\/\/developer.android.com\/reference\/android\/widget\/CursorAdapter.html#setFilterQueryProvider%28android.widget.FilterQueryProvider%29\"><code>adapter.setFilterQueryProvider<\/code><\/a>.<\/li>\n<\/ul>\n<p>This allows a significant refactoring of the <code>SelectState<\/code> class. Instead of the subclassed Adapter class, I&#8217;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&#8217;ve replaced.<\/p>\n<p>The re-written <code>SelectState<\/code> follows. The full example can be <a href=\"http:\/\/static.outofwhatbox.com\/AndroidAutoText\/AutoCompleteInnerClasses.zip\">downloaded as a ZIP file<\/a>.<\/p>\n<p>(See the <a href=\"http:\/\/www.outofwhatbox.com\/blog\/2010\/11\/android-autocompletetextview-sqlite-and-dependent-fields\/\">earlier post<\/a> for a description of the sample application&#8217;s functionality.)<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage org.oowb.AutoCompleteExample;\r\n\r\nimport android.app.Activity;\r\nimport android.database.Cursor;\r\nimport android.os.Bundle;\r\nimport android.view.View;\r\nimport android.widget.AdapterView;\r\nimport android.widget.AutoCompleteTextView;\r\nimport android.widget.Button;\r\nimport android.widget.FilterQueryProvider;\r\nimport android.widget.SimpleCursorAdapter;\r\nimport android.widget.TextView;\r\nimport android.widget.AdapterView.OnItemClickListener;\r\nimport android.widget.SimpleCursorAdapter.CursorToStringConverter;\r\n\r\n\/**\r\n * A simple Android Activity to demonstrate:\r\n * \r\n * 1) How to use an AutoCompleteTextView with a SimpleCursorAdapter\r\n * \r\n * 2) How to access the cursor row for the user's choice, to obtain additional\r\n * 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    final static int[] to = new int[] { android.R.id.text1 };\r\n    final static String[] from = new String[] { &quot;state&quot; };\r\n\r\n    private TextView mStateCapitalView;\r\n    private AutoCompleteTextView mStateNameView;\r\n    private AutoCompleteDbAdapter mDbHelper;\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        mDbHelper = 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 a SimpleCursorAdapter for the State Name field.\r\n        SimpleCursorAdapter adapter = \r\n            new SimpleCursorAdapter(this, \r\n                    android.R.layout.simple_dropdown_item_1line, null,\r\n                    from, to);\r\n        mStateNameView.setAdapter(adapter);\r\n\r\n        \/\/ Set an OnItemClickListener, to update dependent fields when\r\n        \/\/ a choice is made in the AutoCompleteTextView.\r\n        mStateNameView.setOnItemClickListener(new OnItemClickListener() {\r\n            public void onItemClick(AdapterView&lt;?&gt; listView, View view,\r\n                        int position, long id) {\r\n                \/\/ Get the cursor, positioned to the corresponding row in the\r\n                \/\/ 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 = \r\n                    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        \/\/ Set the CursorToStringConverter, to provide the labels for the\r\n        \/\/ choices to be displayed in the AutoCompleteTextView.\r\n        adapter.setCursorToStringConverter(new CursorToStringConverter() {\r\n            public String convertToString(android.database.Cursor cursor) {\r\n                \/\/ Get the label for this row out of the &quot;state&quot; column\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        \/\/ Set the FilterQueryProvider, to run queries for choices\r\n        \/\/ that match the specified input.\r\n        adapter.setFilterQueryProvider(new FilterQueryProvider() {\r\n            public Cursor runQuery(CharSequence constraint) {\r\n                \/\/ Search for states whose names begin with the specified letters.\r\n                Cursor cursor = mDbHelper.getMatchingStates(\r\n                        (constraint != null ? constraint.toString() : null));\r\n                return cursor;\r\n            }\r\n        });\r\n    }\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>AutoCompleteTextView doesn&#8217;t require subclassing the CursorAdapter, after all. Where I&#8217;d thought it would be necessary to override certain methods, I&#8217;ve found that handler methods provided by SimpleCursorAdapter allow the same functionality without subclassing.<\/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\/663"}],"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=663"}],"version-history":[{"count":5,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts\/663\/revisions"}],"predecessor-version":[{"id":668,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/posts\/663\/revisions\/668"}],"wp:attachment":[{"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/media?parent=663"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/categories?post=663"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.outofwhatbox.com\/blog\/wp-json\/wp\/v2\/tags?post=663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}