Android拨号搜索机制源码分析(原)

        本文主要介绍Android4.4拨号界面的联系人搜索机制

        拨号搜索机制分为两个部分,引导搜索和搜索。其中引导搜索是指,从用户输入到开始搜索之间的流程,而搜索部分是指,从数据库搜索字符串的过程。


一、引导搜索部分


        默认的拨号界面的布局从上到下主要分为3个部分:显示列表、数字编辑框、拨号键盘。他们的作用是:用户直接在拨号键盘上输入数字,然后数字编辑框显示所输入的数字,同时在显示列表中体现此时的搜索结果。如图所示:

        从流程上来讲,需要拨号键盘将用户点击转换为按键事件并传递给编辑框,然后由编辑框传递给搜索框,再由搜索框传递给列表Fragment,然后在列表所加载的Adapter中体现当前的搜索结果。
        接下来我们详细分析这个过程。


1.1、从拨号键盘到编辑框


        用户在拨号键盘上的点击的数字按钮,都会在编辑框中体现出来,我们先来追踪这一过程。
        每个拨号键盘按钮都是DialpadKeyButton类型的View,他们继承自FrameLayout,当遇到点击事件时,就会触发setPressed()方法:

        @setPressed
        public void setPressed(boolean pressed) {
            super.setPressed(pressed);
            if (mOnPressedListener != null) {
                mOnPressedListener.onPressed(this, pressed);
            }
        }
        然后将事件转换为onPressed()发送给mOnPressedListener,这个mOnPressedListener就是DialpadFragment,然后在DialpadFragment的onPressed()中,将当前的点击事件转换为标准的按键输入:
        @DialpadFragment.java
        public void onPressed(View view, boolean pressed) {
            if (pressed) {
                switch (view.getId()) {
                    case R.id.one: {
                       //将当前点击事件转换为键盘事件
                       keyPressed(KeyEvent.KEYCODE_1);
                       break;
                    }
                    case R.id.two: {
                       keyPressed(KeyEvent.KEYCODE_2);
                       break;
                    }
                    default: {
                         Log.wtf(TAG, "Unexpected onTouch(ACTION_DOWN) event from: " + view);
                         break;
                    }
                }
            } else {
            }
        }
        这里看到,当我们在拨号键盘上点击某个View时,将会通过onPressed()转换为标准的键盘消息,比如,在R.id.one控件上的点击,将会转换为KeyEvent.KEYCODE_1消息。然后在keyPressed()中将会把当前输入传递给编辑框:
        private void keyPressed(int keyCode) {
            mHaptic.vibrate();
            KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
            //传递给编辑框控件
            mDigits.onKeyDown(keyCode, event);

            // If the cursor is at the end of the text we hide it.
            final int length = mDigits.length();
            if (length == mDigits.getSelectionStart() && length == mDigits.getSelectionEnd()) {
                mDigits.setCursorVisible(false);
            }
        }

        上面的mDigits就是显示当前输入内容的编辑框控件。


1.2、从编辑框到搜索框


        搜索框的作用主要是,当拨号键盘隐藏时,显示当前的输入内容。而编辑框需要将当前的输入传递给搜索框。
        当编辑框检测到KeyDown事件后,就会将当前键盘的输入放入编辑框中,并触发TextWatcher的相关方法:
        @DialpadFragment.java
        public void afterTextChanged(Editable input) {
            if (!mDigitsFilledByIntent && SpecialCharSequenceMgr.handleChars(getActivity(), input.toString(), mDigits)) {
                mDigits.getText().clear();
            }

            if (isDigitsEmpty()) {
                mDigitsFilledByIntent = false;
                mDigits.setCursorVisible(false);
            }

            if (mDialpadQueryListener != null) {
                //传递给mDialpadQueryListener
                mDialpadQueryListener.onDialpadQueryChanged(mDigits.getText().toString());
            }
            updateDialAndDeleteButtonEnabledState();
        }
        在这里,又将当前已经输入的文本传递给mDialpadQueryListener,它是在DialtactsActivity中实现的:
        @DialtactsActivity.java
        public void onDialpadQueryChanged(String query) {
            final String normalizedQuery = SmartDialNameMatcher.normalizeNumber(query, SmartDialNameMatcher.LATIN_SMART_DIAL_MAP);
            if (!TextUtils.equals(mSearchView.getText(), normalizedQuery)) {
                if (mDialpadFragment == null || !mDialpadFragment.isVisible()) {
                    return;
                }
                //传递给搜索框
                mSearchView.setText(normalizedQuery);
            }
        }

        我们看到,在onDialpadQueryChanged()中将当前编辑框的内容通过setText()方法传递给了mSearchView,也就是最上方的搜索框。


1.3、从搜索框到搜索结果列表Fragment


        搜索框下面的列表用于在搜索时显示搜索结果,他所处的位置是复用的,可以选择性的加载三种Fragment, 当处于非搜索状态时,加载PhoneFavoriteFragment,这是进入拨号界面的默认加载项,将会显示瓦片式收藏界面,当在搜索模式时,将会加载SmartDialSearchFragment或者RegularSearchFragment用于显示当时的搜索结果。对于最常用的用户在拨号键盘输入内容触发的搜索,将会加载SmartDialSearchFragment。此时搜索框需要将要搜索的文本传递给SmartDialSearchFragment。
        在搜索时,由于搜索框注册了文本监听器,所以将会触发TextWatcher,此时需要暂存当前要搜索的文本,并进入搜索模式,然后再将搜索内容交给SmartDialSearchFragment。
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            final String newText = s.toString();
            if (newText.equals(mSearchQuery)) {
                return;
            }
            //存储当前的搜索文本
            mSearchQuery = newText;
            final boolean dialpadSearch = isDialpadShowing();

            // Show search result with non-empty text. Show a bare list otherwise.
            if (TextUtils.isEmpty(newText) && getInSearchUi()) {
                //退出搜索模式
                exitSearchUi();
                mSearchViewCloseButton.setVisibility(View.GONE);
                mVoiceSearchButton.setVisibility(View.VISIBLE);
                return;
            } else if (!TextUtils.isEmpty(newText)) {
                final boolean sameSearchMode = (dialpadSearch && mInDialpadSearch) || (!dialpadSearch && mInRegularSearch);
                if (!sameSearchMode) {
                    //进入搜素模式
                    enterSearchUi(dialpadSearch, newText);
                }

                if (dialpadSearch && mSmartDialSearchFragment != null) {
                    //将搜索文本转交给mSmartDialSearchFragment
                    mSmartDialSearchFragment.setQueryString(newText, false);
              
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值