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:

  1. onQueryTextChange: Called when the user enters characters in the search field.
  2. 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.

Create a Free Account

Register now and get access to our Cloud Services.

Posts you might be interested in: