Android Api Demos登顶之路(五十二)Search

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>

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 13:20:20

Android Api Demos登顶之路(五十二)Search的相关文章

Android Api Demos登顶之路(十四)Quick Contacts

这个demeo主要演示的是使内容提供者和内容解析者来获取其它应用的数据.Content Provider为不同应用之间共享数据提供了统一的接口,Android系统的每个Content Provider都定义了一个CONTENT_URI,Android中每个Context对象(如Activity)对含有一个ContentResolver,ContentResolver可以根据CONTENT_URI获取对应的Content Provider. 在本例中使用了startManagingCursor(c

Android Api Demos登顶之路(四十五)Loader--&amp;gt;Cursor

这个demo演示了类载入器的用法.关于类载入器的使用我们在前面的demo中已经介绍过了 在此再小小的复习一下. 类载入器的使用步骤: * 1.获取类载入器的管理者LoaderManager manager = tent.getLoaderManager(); * 2.初始化loader MainActivity public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedIn

Android Api Demos登顶之路(四十)Fragment--&gt;Layout

这个demo演示了fragment的布局特点.本例中在竖屏的状态下,当我们点击列表的条目时 打一个activity来显示这个条目的详细信息. * 而在横屏的状态下由于屏幕足够宽,我们就在界面上同时显示了两个fragment,一个用来 显示标题,另一个用来显示详细信息. layout目录下创建竖屏显示的布局文件:fragment_layout.xml <?xml version="1.0" encoding="utf-8"?> <FrameLayou

Android Api Demos登顶之路(三十)Display Options

这个demo演示了actionbar的各种布局样式. activity_main.xml <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&

Android Api Demos登顶之路(四十七)Loader--&gt;Throttle

这个demo演示了如何利用类加载器对自定义的内容提供者共享的数据进行管理 MainActivity public class MainActivity extends Activity { // 定义主机名,用以拼接Uri,Uri表明了内容提供的地址,外部应用通过Uri访问内容提供者,来实现对数据的增删改查 private static final String AUTHORITY = "com.fishtosky.loaderthrottle"; /* * 本例中我们将自定义的一个数

测开之路五十二:蓝图的用法

目录结构 html <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>蓝图渲染</title></head><body><h1>这里是蓝图渲染</h1></body></html> 子app(创建不同的蓝图,如接口测试.ui测试.性能测试)

全栈JavaScript之路(十二)了解 Selector API

2008 年之前,浏览器中几乎所有的DOM扩展都是专有的.此后,W3C 着手将一些已经成为事实标准的专有扩展标准化并写入规范当中. Selector API  level 1  的核心是两个方法: querySelector(), querySelectorAll() .在兼容浏览器中可以通过Docuemnt 类型节点,或者Element类型节点调用. 目前已完全支持Selectors API Level 1的浏览器有IE 8+.Firefox 3.5+.Safari 3.1+.Chrome 和

QT开发(五十二)———QML语言

QT开发(五十二)---QML语言 QML是一种声明语言,用于描述程序界面.QML将用户界面分解成一块块小的元素,每一元素都由很多组件构成.QML定义了用户界面元素的外观和行为:更复杂的逻辑则可以结合JavaScript脚本实现. 一.QML基础语法 1.Import语句 QML代码中,import语句一般写在头几行,主要用途如下:     A.包含类型的全名空间     B.包含QML代码文件的目录     C.JavaScript代码文件 格式如下: import Namespace Ver

第五十二个知识点:选择一个先进的应用概念,如电子投票,拍卖或多方计算。这样一个系统的大致安全需求是什么

第五十二个知识点:选择一个先进的应用概念,如电子投票,拍卖或多方计算.这样一个系统的大致安全需求是什么 这是我们认为每个密码学博士一年级都应该知道的52件事中的最后一件.你可能已经收集了过去的52个博客,我们希望学生知道从理论到实践的各个方面.但关键是你需要在密码学中考虑的不仅是对遵守规则的玩家的安全,还有对不遵守规则的玩家的安全.让我们从投票.拍卖和多方计算的角度来研究这个问题. 让我们先讨论一下三个应用程序的含义. 在投票中,我们根绝投票者进行一些投票方案(得票最多者当选.多选.赞成投票或其