Android SearchView and DataBinding: A Step-by-Step Guide
In this blog post, we show you how to develop an Android application with a SearchView, which allows you to search a ListView for specific terms. We use DataBinding to link layouts in activities and adapters. DataBinding is a useful technique to make the code clearer and more efficient.
What is the Android SearchView?
The Android SearchView is a widget that provides search functionality within your app. It can be used in both the ToolBar/ActionBar and within a layout. Available since Android 3.0, it offers many features like text search, suggestions, and even voice search.
A simple implementation in an XML layout looks like this:
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
In this example, we use the SearchView.OnQueryTextListener interface and the Filterable interface to handle search queries. OnQueryTextListener allows us to capture two key events:
- onQueryTextChange: Called when the user enters characters in the search field.
- onQueryTextSubmit: Triggered when the user submits the search query.
Implementing an Example of Android SearchView
In the following example, we create an activity that contains a SearchView and a ListView. The ListView is filled with a list of month names, which we filter using the search query.
activity_main.xml
The main layout consists of a SearchView and a ListView:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true" />
<ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/search" />
</RelativeLayout>
</layout>
MainActivity.java
In the MainActivity, we use DataBinding to link the view components to the code. We also create an ArrayList of month names and set up an Adapter to display this list in the ListView. The search queries are filtered by calling the adapter’s filter method whenever the text in the SearchView changes.
package com.example.searchviewexample;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import com.example.searchviewexample.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
ListAdapter adapter;
List<String> monthList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Filling month names
monthList.add("January");
monthList.add("February");
monthList.add("March");
monthList.add("April");
monthList.add("May");
monthList.add("June");
monthList.add("July");
monthList.add("August");
monthList.add("September");
monthList.add("October");
monthList.add("November");
monthList.add("December");
// Setting up the adapter for the list
adapter = new ListAdapter(monthList);
binding.listView.setAdapter(adapter);
// Configuring SearchView
binding.search.setActivated(true);
binding.search.setQueryHint("Enter search term");
binding.search.onActionViewExpanded();
binding.search.setIconified(false);
binding.search.clearFocus();
// Adding search functionality
binding.search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
}
ListAdapter.java
The adapter binds the data to the ListView. Here we use the Filterable interface to filter the list based on the search query.
package com.example.searchviewexample;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.example.searchviewexample.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;
public class ListAdapter extends BaseAdapter implements Filterable {
List<String> dataList;
List<String> filteredList;
ValueFilter valueFilter;
private LayoutInflater inflater;
public ListAdapter(List<String> list) {
dataList = list;
filteredList = list;
}
@Override
public int getCount() {
return dataList.size();
}
@Override
public String getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null) {
inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
RowItemBinding rowBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
rowBinding.stringName.setText(dataList.get(position));
return rowBinding.getRoot();
}
@Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<String> filterList = new ArrayList<>();
for (int i = 0; i < filteredList.size(); i++) {
if (filteredList.get(i).toUpperCase().contains(constraint.toString().toUpperCase())) {
filterList.add(filteredList.get(i));
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = filteredList.size();
results.values = filteredList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
dataList = (List<String>) results.values;
notifyDataSetChanged();
}
}
}
Conclusion
In this example, we created a simple Android application that makes a list of month names searchable. By using DataBinding and the Filterable interface, the code remains clean and structured.