木鸟杂记

大规模数据系统

Android Study Notes (1): Implementing the Search Box

Goal

Enter keywords and display search results in real time.

Author: Muniao Notes https://www.qtmuniao.com. Please indicate the source when reposting.

Process

Starting from the official documentation, since I was a beginner and knew few related terms, and the document was not a code-level implementation, I failed to build a complete search framework. The document mainly covers the following points:

  1. Two implementation methods: search dialog and search widget; for devices running Android 3.0 and later, the latter is recommended as it is more flexible.
  2. Three main components:
    • Searchable configuration (a searchable configuration)
    • Searchable container (a searchable Activity) (Confusion point 1)
    • Search interface (a search interface)
  3. Search process:
    • Accept the query (Receive the query)
      Using Intent (Confusion point 2)
    • Search data (Search your data)
    • Present results (Present the results) (Confusion point 3)

I wanted to use the Search Widget approach and encountered the following confusion points:

  1. How to trigger a search in Activity—that is, how to make the search icon appear in the upper-right corner of the AppBar.
  2. If using Intent to query data, as in the examples, it should not be possible to match input characters in real time. I guessed there should be something like a listener, but the example didn’t provide one.
  3. How to present results: the documentation suggests having SearchableActivity inherit from ListView, but specific details, such as how to receive results and pass them to ListView, were not mentioned.
    In short, none of the three steps in the search process was clear to me; I was completely baffled.

So I searched for the keywords “SearchView action bar” and found a post: Implementing SearchView in action bar. After studying it carefully, I figured out the above issues.

First, regarding triggering the search, the answer uses an Activity with an App Bar as the SearchableActivity, overrides the onCreateOptionsMenu function, instantiates its menu parameter, and adds the SearchView as one of its items. This way, a search button appears in the upper-right corner of the SearchableActivity. The relevant code is as follows:
res\menu\search.xml:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/search_menu"
android:title="@string/search_hint"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.widget.SearchView" />

</menu>

SearchableActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
this.menu = menu;

// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.search_menu).getActionView();
// Assumes current activity is the searchable activity
ComponentName name = getComponentName();
searchView.setSearchableInfo(searchManager.getSearchableInfo(name));
searchView.setIconifiedByDefault(false);

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
doMySearch(s);
return false;
}

@Override
public boolean onQueryTextChange(String s) {
doMySearch(s);
return false;
}
});

return true;
}

AndroidManifest.xml

1
2
3
4
5
6
7
<activity android:name=".SearchableActivity">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>

res/xml/searchable.xml

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/app_label" >
</searchable>

Second, for real-time matching of query results: this is also done in the onCreateOptionsMenu function by setting listeners for the SearchView. See the code above for details, but I haven’t yet figured out the difference between returning true and false.

Finally, displaying data: as the official documentation says, use ListView. The specific approach is to pass data (e.g., List<String>) to a ListView inflated from XML via an Adapter. The answer uses CursorAdapter (more suitable for database data). The specific code is as follows:
res/layout/item.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

ResultAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ResultAdapter extends CursorAdapter {
private List<String> items;
private TextView text;

public ResultAdapter(Context context, Cursor cursor, List<String> items) {
super(context, cursor, false);
this.items = items;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
text.setText(items.get(cursor.getPosition()));
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.item, parent, false);
text = view.findViewById(R.id.item);
return view;
}
}

SearchableActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void doMySearch(String query){
String[] columns = new String[] { "_id", "text" };
Object[] temp = new Object[] { 0, "default" };

MatrixCursor cursor = new MatrixCursor(columns);
for(int i = 0; i < items.size(); i++) {

temp[0] = i;
temp[1] = items.get(i);
cursor.addRow(temp);

}

// SearchView
final SearchView search = (SearchView) menu.findItem(R.id.search_menu).getActionView();
search.setSuggestionsAdapter(new ResultAdapter(this, cursor, items));
}

References:

  1. Android Official Documentation, https://developer.android.com/guide/topics/search/search-dialog.html
  2. Stack Overflow Answer, https://stackoverflow.com/questions/21585326/implementing-searchview-in-action-bar
  3. Official Video, https://www.youtube.com/watch?v=9OWmnYPX1uc

我是青藤木鸟,一个喜欢摄影、专注大规模数据系统的程序员,欢迎关注我的公众号:“木鸟杂记”,有更多的分布式系统、存储和数据库相关的文章,欢迎关注。 关注公众号后,回复“资料”可以获取我总结一份分布式数据库学习资料。 回复“优惠券”可以获取我的大规模数据系统付费专栏《系统日知录》的八折优惠券。

我们还有相关的分布式系统和数据库的群,可以添加我的微信号:qtmuniao,我拉你入群。加我时记得备注:“分布式系统群”。 另外,如果你不想加群,还有一个分布式系统和数据库的论坛(点这里),欢迎来玩耍。

wx-distributed-system-s.jpg