I have implemented a Searchview into my application, and have run into a weird problem. Basically, the user is able to enter a string to be searched and it is submitted properly. However, my application will filter the ListView based on the search query, and then an Intent will be launched resulting in the activity starting again and returning to it's original state where it is displaying all the results.
Here is the related code.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
...
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
updateEntriesView(dbHelper.queryByName(query));
Toast.makeText(getApplicationContext(), "Searching for " + query, Toast.LENGTH_LONG).show();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
private void updateEntriesView(ArrayList<Entry> response) {
mListView = (ListView) findViewById(R.id.listview_entries);
if (adapter == null) {
adapter = new EntryListAdapter(EntriesActivity.this, R.layout.row_entry_layout, response);
mListView.setAdapter(adapter);
} else {
adapter.clear();
adapter.addAll(response);
adapter.notifyDataSetChanged();
}
adapter.setNotifyOnChange(true);
}
I can not figure out to change this behavior and I can not find any documentation regarding it's implementation online. Is there a way I can override this feature and prevent it from launching an intent and restarting the activity to it's original unfiltered state?
EDIT:
I was able to solve this issue myself. For anyone who may be having the same problem here was my solution.
So I had an intent-filter in my AndroidManifest.xml under the activity that would launch an intent upon a search action. This is what was causing it to launch an intent and start a new instance of my activity.
My solution to this was to convert this activity into a single top activity and add code to handle the intent. By making the activity single top, it allows the activity to handle incoming intents without starting up a new instance of the intent. For a more detailed description on the difference between a normal and single top activity, this is a good article on the subject https://www.mobomo.com/2011/06/android-understanding-activity-launchmode/
Now, because my activity is single top, I can override the onNewIntent() method and add my code for handling this intent without having it launch a new instance. The relevant code for solving my problem is below.
AndroidManifest.xml
<activity android:name=".EntriesActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable"></meta-data>
</activity>
EntriesActivity.java
public class EntriesActivity extends AppCompatActivity {
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
...
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
updateEntriesView(dbHelper.queryByName(query));
Toast.makeText(getApplicationContext(), "Searching for " + query, Toast.LENGTH_LONG).show();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
updateEntriesView(dbHelper.queryEntriesByName(query));
}
}
private void updateEntriesView(ArrayList<Entry> response) {
if (adapter == null) {
adapter = new EntryListAdapter(EntriesActivity.this, R.layout.row_entry_layout, response);
mEntriesList.setAdapter(adapter);
} else {
adapter.clear();
adapter.addAll(response);
adapter.notifyDataSetChanged();
}
adapter.setNotifyOnChange(true);
}
}
I hope this helps.