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

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

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

一、引导搜索部分

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

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

1.1、从拨号键盘到编辑框

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

@setPressedpublic void setPressed(boolean pressed) {super.setPressed(pressed);if (mOnPressedListener != null) {mOnPressedListener.onPressed(this, pressed);}} 然后将事件转换为onPressed()发送给mOnPressedListener,这个mOnPressedListener就是DialpadFragment,然后在DialpadFragment的onPressed()中,将当前的点击事件转换为标准的按键输入:@DialpadFragment.javapublic 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.javapublic 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) {//传递给mDialpadQueryListenermDialpadQueryListener.onDialpadQueryChanged(mDigits.getText().toString());}updateDialAndDeleteButtonEnabledState();} 在这里,又将当前已经输入的文本传递给mDialpadQueryListener,它是在DialtactsActivity中实现的:@DialtactsActivity.javapublic 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) {//将搜索文本转交给mSmartDialSearchFragmentmSmartDialSearchFragment.setQueryString(newText, false);} else if (mRegularSearchFragment != null) {mRegularSearchFragment.setQueryString(newText, false);}mSearchViewCloseButton.setVisibility(View.VISIBLE);mVoiceSearchButton.setVisibility(View.GONE);return;}} 在这里完成了三个重要任务: 1、将当前要搜索的文本存储在mSearchQuery中,在当前界面被恢复时使用; 2、进入/退出搜素界面,也就是配置当前需要加载的Fragment;

3、将要搜素的文本传递给搜索列表的Fragment,也就是mSmartDialSearchFragment;

1.4、从搜索列表的Fragment到Adapter也就越容易失败,还不如怀揣一颗平常心,“但行好事,莫问前程”,往往成功的几率反而更大些

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

相关文章:

你感兴趣的文章:

标签云: