android 为所有需要提供查询功能的activity提供了两种查询方式:search dialog 和searchview
* 这个demo演示了第一种查询方式。
* 基本思路:用户提交查询后,Android系统构造一个Intent并把用户的查询内容放在这个Intent中。然后Android启动你定义的用来处理用户查询的Activity(称为Searchable Activity),并把这个Intent发给该Activity。
* 使用SearchDialog的步骤
* 1.在res/xml目录下创建searchable.xml,用于描述searchdialog的一些属性。
* 2.创建SearchableActivity,这里需要注意的是由于该activity需要验证是否是由查询意图启动的所以在对该activity进行配置时必须在过滤器中指明android.intent.action.SEARCH, 并在meta-data部分指定searchable configuration (指向res/xml/searchable.xml)
* 3.调用:Search Dialog 为屏幕上方的浮动窗口,缺省为不可见的。只有当调用onSearchRequested()或是用户按“Search”键时(不是所有设备都有Search钮,在模拟器上可以用F5)Search Dialog才会显示。
* Searchable.xml,这里需要注意的是在定义label、hint等属性时必须通过String进行引用,否则设置的内容将不起作用,可能会造成searchdialog无法启动,或者某些功能无法实现。
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_lable"
android:hint="@string/search_hint"
android:icon="@drawable/star_big_on"
android:searchMode="showSearchIconAsBadge"
android:searchSuggestAuthority="com.fishtosky.invokesearch.SearchSuggestionSampleProvider"
android:searchSuggestSelection=" ? ">
</searchable>
定义SearchableActivity的布局文件:search_result.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这个Activity用来处理用户查询请求,本例只是简单地显示了一下查询内容"/>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Query String:"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/query_string"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Query App Data:"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/query_data"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Activity Method:"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/activity_method"/>
</LinearLayout>
</LinearLayout>
主布局文件:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/info" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="ways to invoke search" />
<Button
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Search" />
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Opertional search parameters" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Prefill Query:" />
<EditText
android:focusable="true"
android:focusableInTouchMode="true"
android:id="@+id/et_query"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="App Data:" />
<EditText
android:id="@+id/et_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
SearchSuggestionSampleProvider
public class SearchSuggestionSampleProvider extends
SearchRecentSuggestionsProvider {
static final String AUTHORITY="com.fishtosky.invokesearch.SearchSuggestionSampleProvider";
//在此种模式下数据库会记录当前的请求
static final int MODE=DATABASE_MODE_QUERIES;
public SearchSuggestionSampleProvider() {
super();
setupSuggestions(AUTHORITY, MODE);
}
}
SearchableActivity:SearchQueryResult
public class SearchQueryResult extends Activity {
private TextView mQueryString, mQueryData, mActivityMehtod;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_result);
mQueryString = (TextView) findViewById(R.id.query_string);
mQueryData = (TextView) findViewById(R.id.query_data);
mActivityMehtod = (TextView) findViewById(R.id.activity_method);
// 获取意图
Intent queryIntent = getIntent();
// 判断一下这个意图是否是由用户提交查询时所发出的
if (Intent.ACTION_SEARCH.equals(queryIntent.getAction())) {
// 处理查询请求
doSearchQuery(queryIntent, "onCreate()");
} else {
// 如果获取到其它的意图
mActivityMehtod.setText("onCreate(), but no ACTION_SEARCH intent");
}
}
/*
* ActivityA已经启动过,处于当前应用的Activity堆栈中;
* 当ActivityA的LaunchMode为SingleTop时,如果ActivityA在栈顶,
* 且现在要再启动ActivityA,这时会调用onNewIntent()方法
* 当ActivityA的LaunchMode为SingleInstance,SingleTask时,
* 如果已经ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法
* 当ActivityA的LaunchMode为Standard时,由于每次启动ActivityA都是启动新的实例,
* 和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法
*/
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// 处理查询请求
doSearchQuery(intent, "onNewIntent()");
} else {
// 如果获取到其它的意图
mActivityMehtod
.setText("onNewIntent(), but no ACTION_SEARCH intent");
}
}
private void doSearchQuery(Intent queryIntent, String entrypoint) {
String queryString = queryIntent.getStringExtra(SearchManager.QUERY);
mQueryString.setText(queryString);
// 在最近查询列表中记录查询操作
SearchRecentSuggestions suggestion = new SearchRecentSuggestions(this,
SearchSuggestionSampleProvider.AUTHORITY,
SearchSuggestionSampleProvider.MODE);
suggestion.saveRecentQuery(queryString, null);
Bundle appData=queryIntent.getBundleExtra(SearchManager.APP_DATA);
if(appData==null){
mQueryData.setText("<no app data bundle>");
}else{
String data=appData.getString("demo_key");
mQueryData.setText((data==null) ? "<no app data bundle>":data);
}
mActivityMehtod.setText(entrypoint);
}
}
MainActivity
public class MainActivity extends Activity {
private Button mSearch;
private Spinner mSpinner;
private EditText et_query;
private EditText et_data;
/*
* 定义资源数组R.array.search_menumodes中每个条目序号的常量值,所以这里为赋值为0
* 的必须与资源数组中的第一项对应,赋值为1的必须与第二项对应...
*/
private static final int MENUMODE_SEARCH_KEY = 0;
private static final int MENUMODE_MENUITEM = 1;
private static final int MENUMODE_TYPE_TO_SEARCH = 2;
private static final int MENUMODE_DISABLED = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSearch = (Button) findViewById(R.id.search);
mSpinner = (Spinner) findViewById(R.id.spinner);
et_query = (EditText) findViewById(R.id.et_query);
et_data = (EditText) findViewById(R.id.et_data);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.search_menumodes,
android.R.layout.simple_spinner_item);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
if (position == MENUMODE_TYPE_TO_SEARCH) {
/*
* 设置键盘的输入模式,在该应用的界面下铵任意键将调用应用本身定义的搜索功能
* 如果应用本身未定义搜索功能,则此按键模式不起作用,在本例中由于edittext会
* 抢占焦点,所以这项设置的作用也不大
*/
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
} else {
// 设置键盘输入模式为禁用,即在activity下按键将没有任何作用(即启动某项功能的
// 快捷键或者按任意键启动搜索功能都将不可用)
setDefaultKeyMode(DEFAULT_KEYS_DISABLE);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
setDefaultKeyMode(DEFAULT_KEYS_DISABLE);
}
});
mSearch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSearchRequested();
}
});
}
/*
* 重写onSearchRequested()方法,当客户端发送启动搜索功能的信号后会将调用此方法
* 重写该方法我们可以插入本应用中的数据或是上下文中定义的数据搜索功能被启动返回true否则返回false
*/
@Override
public boolean onSearchRequested() {
if (mSpinner.getSelectedItemPosition() == MENUMODE_DISABLED) {
return false;
}
// 预先输入要查询的内容
String queryPrefill = et_query.getText().toString();
String queryData = et_data.getText().toString();
// 利用bundle传递一个上下文中声明的数据,bundle可以传递任意类型的数据
Bundle bundle = null;
if (queryData != null) {
bundle = new Bundle();
bundle.putString("demo_key", queryData);
}
// 启动搜索功能
startSearch(queryPrefill, false, bundle, false);
return true;
}
// 点击menu键时调用此方法
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// 先将菜单置空
if (menu.hasVisibleItems()) {
menu.removeItem(0);
menu.removeItem(1);
}
// 根据下拉列表的选择条目添加菜单
switch (mSpinner.getSelectedItemPosition()) {
case MENUMODE_SEARCH_KEY:
menu.add(0, 0, 0, "(search key)");
break;
case MENUMODE_MENUITEM:
// 添加并设置菜单的快捷键
menu.add(0, 0, 0, "search").setAlphabeticShortcut(
SearchManager.MENU_KEY);
break;
case MENUMODE_TYPE_TO_SEARCH:
menu.add(0, 0, 0, "(type-to-search)");
break;
case MENUMODE_DISABLED:
menu.add(0, 0, 0, "(disabled)");
break;
}
menu.add(0, 1, 0, "Clear History");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
switch (mSpinner.getSelectedItemPosition()) {
case MENUMODE_SEARCH_KEY:
new AlertDialog.Builder(this)
.setMessage(
"To invoke search, dismiss this dialog and press the search key"
+ " (F5 on the simulator).")
.setPositiveButton("OK", null).show();
break;
case MENUMODE_MENUITEM:
onSearchRequested();
break;
case MENUMODE_TYPE_TO_SEARCH:
new AlertDialog.Builder(this)
.setMessage(
"To invoke search, dismiss this dialog and srart typing.")
.setPositiveButton("OK", null).show();
break;
case MENUMODE_DISABLED:
new AlertDialog.Builder(this)
.setMessage("You have disabled search.")
.setPositiveButton("OK", null).show();
break;
}
break;
case 1:
clearSearchHistory();
default:
break;
}
return super.onOptionsItemSelected(item);
}
// 清空搜索记录
private void clearSearchHistory() {
SearchRecentSuggestions suggestion = new SearchRecentSuggestions(this,
SearchSuggestionSampleProvider.AUTHORITY,
SearchSuggestionSampleProvider.MODE);
suggestion.clearHistory();
}
}
在配置文件中进行配置
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value="com.fishtosky.invokesearch.SearchQueryResult"/>
</activity>
<activity
android:name="com.fishtosky.invokesearch.SearchQueryResult"
android:label="@string/result_label"
android:launchMode="singleTop">
<intent-filter >
<action android:name="android.intent.action.SEARCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
<provider android:name="com.fishtosky.invokesearch.SearchSuggestionSampleProvider"
android:authorities="com.fishtosky.invokesearch.SearchSuggestionSampleProvider"></provider>
版权声明:本文为博主原创文章,未经博主允许不得转载。