04-17 13:38:13.690 1030 1451 I ActivityTaskManager: START u0 {act=android.settings.APP_SEARCH_SETTINGS pkg=com.android.settings.intelligence cmp=com.android.settings.intelligence/.search.SearchActivity (has extras)} from uid 1000
清单文件下关于SearchActivity的声明如下:
<activity
android:name=".search.SearchActivity"
android:exported="true"
android:theme="@style/Theme.Settings.NoActionBar">
<intent-filter priority="-1">
<action android:name="com.android.settings.action.SETTINGS_SEARCH" />
<action android:name="android.settings.APP_SEARCH_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_main);
// Keeps layouts in-place when keyboard opens.
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
if (fragment == null) {
fragmentManager.beginTransaction()
.add(R.id.main_content, new SearchFragment())
.commit();
}
Note:FragmentManager是一个抽象类,根据findFragmentBtId找到对应的Fragment.
2.SearchFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
long startTime = System.currentTimeMillis();
setHasOptionsMenu(true);
final LoaderManager loaderManager = getLoaderManager();
mSearchAdapter = new SearchResultsAdapter(this /* fragment */);
mSavedQueryController = new SavedQueryController(
getContext(), loaderManager, mSearchAdapter);
mSearchFeatureProvider.initFeedbackButton();
if (savedInstanceState != null) {
mQuery = savedInstanceState.getString(STATE_QUERY);
mNeverEnteredQuery = savedInstanceState.getBoolean(STATE_NEVER_ENTERED_QUERY);
mShowingSavedQuery = savedInstanceState.getBoolean(STATE_SHOWING_SAVED_QUERY);
} else {
mShowingSavedQuery = true;
}
mSearchFeatureProvider.updateIndexAsync(getContext(), this /* indexingCallback */);
if (SearchFeatureProvider.DEBUG) {
Log.d(TAG, "onCreate spent " + (System.currentTimeMillis() - startTime) + " ms");
}
}
onCreate()方法如上,创建了一些对象,以及通过 mSearchFeatureProvider.updateIndexAsync()方法初始化数据库.
SearchFragment还继承了SearchView的OnQueryTextListener接口,onQueryTextSubmit()只是保存了查询和隐藏软键盘的操作(提交按钮的点击事件,提交会回调此方法);重点来看看onQueryTextChange()方法(输入框内容改变的时候会回调).
public interface OnQueryTextListener {
boolean onQueryTextSubmit(String var1);
boolean onQueryTextChange(String var1);
}
@Override
public boolean onQueryTextChange(String query) {
if (TextUtils.equals(query, mQuery)) {
return true;
}
mEnterQueryTimestampMs = System.currentTimeMillis();
final boolean isEmptyQuery = TextUtils.isEmpty(query);
// Hide no-results-view when the new query is not a super-string of the previous
if (mQuery != null
&& mNoResultsView.getVisibility() == View.VISIBLE
&& query.length() < mQuery.length()) {
mNoResultsView.setVisibility(View.GONE);
}
mNeverEnteredQuery = false;
mQuery = query;
// If indexing is not finished, register the query text, but don't search.
if (!mSearchFeatureProvider.isIndexingComplete(getActivity())) {
return true;
}
if (isEmptyQuery) {
final LoaderManager loaderManager = getLoaderManager();
loaderManager.destroyLoader(SearchLoaderId.SEARCH_RESULT);
mShowingSavedQuery = true;
mSavedQueryController.loadSavedQueries();
mSearchFeatureProvider.hideFeedbackButton(getView());
} else {
mMetricsFeatureProvider.logEvent(SettingsIntelligenceEvent.PERFORM_SEARCH);
restartLoaders();
}
return true;
}
我们可以清楚地看到当判断不是空查询的时候,会调用方法:restartLoaders().该方法主要通过抽象类LoaderManager的initLoader
去加载数据.
private void restartLoaders() {
mShowingSavedQuery = false;
final LoaderManager loaderManager = getLoaderManager();
loaderManager.restartLoader(
SearchLoaderId.SEARCH_RESULT, null /* args */, this /* callback */);
}
@Override
public Loader<List<? extends SearchResult>> onCreateLoader(int id, Bundle args) {
final Activity activity = getActivity();
switch (id) {
case SearchLoaderId.SEARCH_RESULT:
return mSearchFeatureProvider.getSearchResultLoader(activity, mQuery);
default:
return null;
}
}
/**
* Returns a new loader to get settings search results.
*/
SearchResultLoader getSearchResultLoader(Context context, String query);
@Override
public List<? extends SearchResult> loadInBackground() {
SearchResultAggregator aggregator = SearchResultAggregator.getInstance();
return aggregator.fetchResults(getContext(), mQuery);
}
@NonNull
public synchronized List<? extends SearchResult> fetchResults(Context context, String query) {
final SearchFeatureProvider mFeatureProvider = FeatureFactory.get(context)
.searchFeatureProvider();
final ExecutorService executorService = mFeatureProvider.getExecutorService();
final List<SearchQueryTask> tasks =
mFeatureProvider.getSearchQueryTasks(context, query);
// Start tasks
for (SearchQueryTask task : tasks) {
executorService.execute(task);
}
// Collect results
final Map<Integer, List<? extends SearchResult>> taskResults = new ArrayMap<>();
final long allTasksStart = System.currentTimeMillis();
for (SearchQueryTask task : tasks) {
final int taskId = task.getTaskId();
try {
taskResults.put(taskId,
task.get(SHORT_CHECK_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
} catch (TimeoutException | InterruptedException | ExecutionException e) {
Log.d(TAG, "Could not retrieve result in time: " + taskId, e);
taskResults.put(taskId, Collections.EMPTY_LIST);
}
}
// Merge results
final long mergeStartTime = System.currentTimeMillis();
if (SearchFeatureProvider.DEBUG) {
Log.d(TAG, "Total result loader time: " + (mergeStartTime - allTasksStart));
}
final List<? extends SearchResult> mergedResults = mergeSearchResults(taskResults);
if (SearchFeatureProvider.DEBUG) {
Log.d(TAG, "Total merge time: " + (System.currentTimeMillis() - mergeStartTime));
Log.d(TAG, "Total aggregator time: " + (System.currentTimeMillis() - allTasksStart));
}
return mergedResults;
}