Custom AutoComplete SearchView

I wanted to create a nice search box with autocomplete results dropdown in the ActionBar. I could have used the SearchView widget but I didn't want to create a searchable activity and all the necessary overhead. Instead I used a more lightweight approach with AutoCompleteTextView. I'll explain here the steps needed to be done in order to make it work.

1. MainActivity.java

package com.tutorialsee;

import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import com.tutorealsee.R;

public class MainActivity extends Activity {
private ProgressBar mLoadingIndicator;
public static AutoCompleteTextView autoComplete;
List<ItemDetails> itemList = new ArrayList<ItemDetails>();
String searchstring="";
Context context ;
ImageView search;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context =  this ;
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
autoComplete = ((AutoCompleteTextView) findViewById(R.id.edt_search));
search = (ImageView) findViewById(R.id.search);
autoComplete.setAdapter(new testAdapter(this));
OnItemClickListener itemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,int position, long id) {

/*ItemDetails  item = (ItemDetails) arg0.getAdapter().getItem(position);
android.view.inputmethod.InputMethodManager imm = (android.view.inputmethod.InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(autoComplete.getWindowToken(), 0);*/
autoComplete.setText("");
Toast toast = Toast.makeText(getApplicationContext(), "Your search yielded Good results", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
};

autoComplete.setOnItemClickListener(itemClickListener);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
TextView tvCurrency = (TextView) findViewById(R.id.tv_currency);
outState.putString("currency", tvCurrency.getText().toString());
super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
TextView tvCurrency = (TextView) findViewById(R.id.tv_currency);
tvCurrency.setText(savedInstanceState.getString("currency"));
super.onRestoreInstanceState(savedInstanceState);
}


public class testAdapter extends BaseAdapter implements Filterable {

@SuppressWarnings("unused")
private static final int MAX_RESULTS = 10;
private Context mContext;
private List<ItemDetails> resultList = new ArrayList<ItemDetails>();
List<ItemDetails> itemList = new ArrayList<ItemDetails>();

public testAdapter(Context context) {
mContext = context;
}

@Override
public int getCount() {
return resultList.size();
}

@Override
public ItemDetails getItem(int index) {
return resultList.get(index);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.autocomplete_layout,parent, false);
}

View vi = convertView;
TextView text = (TextView) vi.findViewById(R.id.txt);
TextView price = (TextView) vi.findViewById(R.id.price);
text.setText(getItem(position).getTitle());
price.setText(getItem(position).getPrice());

ImageView image = (ImageView) vi.findViewById(R.id.flag);
Picasso.with(mContext).load("http://homemonkey.com/timthumb.php?src="+ getItem(position).getThumb_Images()+ "&w=70&h=100").placeholder(R.drawable.ic_launcher).into(image);

return vi;
}

@Override
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {

List<ItemDetails> books = findBooks(mContext,constraint.toString());
searchstring=constraint.toString();
// Assign the data to the FilterResults
filterResults.values = books;
filterResults.count = books.size();
}else {
searchstring="";
}
return filterResults;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint,FilterResults results) {
if (results != null && results.count > 0) {
resultList = (List<ItemDetails>) results.values;
new SendRequestExample().execute();
notifyDataSetChanged();

} else {
if(searchstring.length()>3 && searchstring!=null &&autoComplete.getVisibility()==View.VISIBLE)
      {
      new SendRequestExamples().execute();
      }
notifyDataSetInvalidated();
}
}
};

return filter;
}

/**
* Returns a search result for the given book title.
*/
private class SendRequestExample extends AsyncTask<Void, Void, Void> {

@Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
search.setVisibility(View.GONE);

}

@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Thread.currentThread();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mLoadingIndicator.setVisibility(View.GONE);
search.setVisibility(View.VISIBLE);

}

@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
return null;
}
}
private class SendRequestExamples extends AsyncTask<Void, Void, Void> {

@Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
search.setVisibility(View.GONE);
}

@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Thread.currentThread();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mLoadingIndicator.setVisibility(View.GONE);
search.setVisibility(View.VISIBLE);
Toast toast = Toast.makeText(getApplicationContext(), "Your search yielded no results", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}

@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
return null;
}
}
private List<ItemDetails> findBooks(Context context, String bookTitle) {

HttpURLConnection conn = null;
StringBuilder jsonResults = new StringBuilder();
try {
StringBuilder sb = new StringBuilder("************* Your URL  *******************);
URL url = new URL(sb.toString());
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(conn.getInputStream());

// Load the results into a StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
}
} catch (MalformedURLException e) {
Log.e("", "Error processing Places API URL", e);

return itemList;
} catch (IOException e) {
Log.e("", "Error connecting to Places API", e);

return itemList;
} finally {
if (conn != null) {
conn.disconnect();
}
}
try {
itemList.clear();
if (jsonResults.toString().contains("title")) {

for (int i = 0; i < new JSONArray(jsonResults.toString()).length(); i++) {
ItemDetails k = new ItemDetails();

if (new JSONArray(jsonResults.toString()).getString(i) != "null") {
Log.v("nullche",""+ new JSONArray(jsonResults.toString()).getString(i));
JSONObject jobj = new JSONArray(jsonResults.toString()).getJSONObject(i);
@SuppressWarnings("unused")
HashMap<String, String> map = new HashMap<String, String>();

k.setTitle(jobj.getString("title"));
k.setNid(Long.parseLong((String) jobj.get("nid")));
String price = jobj.getString("price");
double f = Double.parseDouble(price);
k.setPrice(String.format("%.2f", new BigDecimal(f)));

if (jobj.getString("category").contains("null")) {
} else {
JSONArray jsonMainNode1 = jobj.optJSONArray("thumb_images");
k.setThumb_Images(jsonMainNode1.getString(0).replace(" ", "%20"));
Log.v("Rtitle", "" + jobj.getString("title"));
}
itemList.add(k);
}else{
}
}
}

} catch (Exception e) {
e.printStackTrace();

return itemList;
}

return itemList;
}
}
}

2. ItemDetails.java

package com.tutorialsee;

import java.io.Serializable;
import java.math.BigDecimal;

@SuppressWarnings("serial")
public class ItemDetails implements  Serializable{

private long nid;
private String title;
private String price;
private CharSequence cost_price;
private String body;
private String care;
private String size;
private String size_chart;
private String thumb_images;
private String fullimages;
private String imagePath;
private String size1;
private long id;
private String image;
public String getImagePath() {
  return imagePath;
}

public void setImagePath(String imagePath) {
  this.imagePath = imagePath;
}
public ItemDetails(long nid, String image, long id, String title, String price, CharSequence cost_price, String body, String care, String size, String size_chart, String thumb_images, String fullimages, String imagePath,String size1){

  this.nid = nid;
  this.title = title;
  this.price = price;
  this.cost_price = cost_price;
  this.body = body;
  this.care = care;
  this.size = size;
  this.size_chart = size_chart;
  this.thumb_images = thumb_images;
  this.fullimages = fullimages;
    this.imagePath = imagePath;
    this.size1=size1;
    this.image = image;
  this.id = id;


}
public String getSizeselected() {
  return size1;
}
public void setSizeselected(String size) {
  this.size1 = size;
}

public String getCare() {
return care;
}
public void setCare(String care) {
this.care = care;
}


public ItemDetails(){
}

public long getNid() {
return nid;
}
public void setNid(long nid) {
this.nid = nid;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public CharSequence getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public CharSequence getCost_Price() {
return cost_price;
}
public void setCost_Price(CharSequence cost_price) {
this.cost_price = cost_price;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getSize_Chart() {
return size_chart;
}
public void setSize_Chart(String size_chart) {
this.size_chart = size_chart;
}
public String getThumb_Images() {
return thumb_images;
}
public void setThumb_Images(String thumb_images) {
this.thumb_images = thumb_images;
}
public String getFullImages() {
return fullimages;
}
public void setFullImages(String fullimages) {
this.fullimages = fullimages;
}
public BigDecimal getPrice1() {
BigDecimal sPrice = new BigDecimal(price);
return (BigDecimal) sPrice;
}
public String getName1() {
return title;
}
}
@SuppressWarnings("serial")
public class ItemDetails implements  Serializable{
public ItemDetails(){
  this.id = id;
  this.image = image;
}
public BigDecimal getPrice1() {
// TODO Auto-generated method stub
return null;
}
public String getName1() {
// TODO Auto-generated method stub
return null;
}
public void setTitle(String string) {
// TODO Auto-generated method stub

}
public void setNid(long parseLong) {
// TODO Auto-generated method stub

}
public void setPrice(String format) {
// TODO Auto-generated method stub

}
public void setThumb_Images(String replace) {
// TODO Auto-generated method stub

}
}

3. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fadingEdge="none" >

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fadingEdge="none" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <RelativeLayout
                android:id="@+id/gallery_paging"
                android:layout_width="fill_parent"
                android:layout_height="270dp"
                android:background="#7F7F7F" >

                <LinearLayout
                    android:id="@+id/image_count"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:layout_alignParentRight="true"
                    android:layout_marginRight="5dp"
                    android:background="#00000000"
                    android:orientation="horizontal" >
                </LinearLayout>
            </RelativeLayout>

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:layout_below="@+id/gallery_paging"
                android:layout_marginTop="5dp"
                android:orientation="vertical" >

                <LinearLayout
                    android:id="@+id/houseCallLayout"
                    android:layout_width="match_parent"
                    android:layout_height="240dp"
                    android:orientation="horizontal"
                    android:weightSum="1" >

                    <ImageView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#009688"
                        android:contentDescription="@null" />

                    <View
                        android:layout_width="6dp"
                        android:layout_height="match_parent"
                        android:background="@android:color/transparent" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#4CAF50"
                        android:orientation="vertical" >

                        <ImageView
                            android:id="@+id/nailLayout"
                            android:layout_width="wrap_content"
                            android:layout_height="120dp"
                            android:background="#FFEB3B"
                            android:contentDescription="@null" />

                        <ImageView
                            android:id="@+id/makeUpLayout"
                            android:layout_width="wrap_content"
                            android:layout_height="120dp"
                            android:layout_marginTop="5dp"
                            android:background="#03A9F4"
                            android:contentDescription="@null" />
                    </LinearLayout>
                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="120dp"
                    android:layout_marginTop="7dp"
                    android:orientation="horizontal"
                    android:weightSum="1" >

                    <ImageView
                        android:id="@+id/BrowLayout"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#795548"
                        android:contentDescription="@null" />

                    <View
                        android:layout_width="6dp"
                        android:layout_height="match_parent"
                        android:background="@android:color/transparent" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#FF5722" >

                        <ImageView
                            android:id="@+id/facialLayout"
                            android:layout_width="wrap_content"
                            android:layout_height="match_parent"
                            android:background="#FF5722"
                            android:contentDescription="@null" />
                    </LinearLayout>
                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="120dp"
                    android:layout_marginBottom="2dp"
                    android:layout_marginTop="7dp"
                    android:orientation="horizontal"
                    android:weightSum="1" >

                    <ImageView
                        android:id="@+id/massage"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#4CAF50"
                        android:contentDescription="@null" />

                    <View
                        android:layout_width="6dp"
                        android:layout_height="match_parent"
                        android:background="@android:color/transparent" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_weight=".5"
                        android:background="#607D8B" >

                        <ImageView
                            android:id="@+id/hairLayout"
                            android:layout_width="wrap_content"
                            android:layout_height="match_parent"
                            android:background="#607D8B"
                            android:contentDescription="@null" />
                    </LinearLayout>
                </LinearLayout>
            </LinearLayout>
        </RelativeLayout>
    </ScrollView>

    <LinearLayout
        android:id="@+id/input"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="60dp"
        android:gravity="center|center_vertical" >

        <AutoCompleteTextView
            android:id="@+id/edt_search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_weight="6.78"
            android:background="#ffffff"
            android:hint="search"
            android:padding="10dp"
            android:paddingLeft="15dp" >

            <requestFocus />
        </AutoCompleteTextView>

        <ImageView
            android:id="@+id/search"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="0.93"
            android:background="#ffffff"
            android:contentDescription="@null"
            android:padding="5dp"
             android:visibility="visible"
            android:src="@drawable/search" />
       
        <ProgressBar
        android:id="@+id/pb_loading_indicator"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
         android:layout_weight="0.93"
        android:background="@drawable/progressimage"
        android:visibility="gone" />
       
    </LinearLayout>
   
    <TextView
        android:id="@+id/tv_currency"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

4. autocomplete_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="horizontal" >

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
  
    android:orientation="horizontal" >
    <ImageView
        android:id="@+id/flag"
        android:layout_width="60dp"
        android:layout_height="70dp"
         android:background="@android:color/white"
          android:layout_marginBottom="0.01dp"
        android:contentDescription="@string/hello_world"
        android:padding="10dp" />
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
     android:layout_marginBottom="0.01dp"
       android:background="@android:color/white"
     android:padding="5dp" >
    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      
        android:text="search"
        android:textSize="15dp" />
     <TextView
        android:id="@+id/price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
         android:text="search"
        android:textSize="15dp" />
     <TextView
        android:id="@+id/nid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
     android:layout_marginTop="3dp"
         android:text="search"
        android:textSize="15dp"
        android:visibility="gone"/>
    </LinearLayout>
</LinearLayout>
</LinearLayout>

5. product.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
     android:background="#ffffff" >

    <ImageView
        android:id="@+id/img_product"
        android:layout_width="120dp"
        android:layout_height="140dp"
        android:layout_marginLeft="5dp"
        android:contentDescription="@drawable/ic_launcher"
        android:paddingTop="10dp"
        android:src="@drawable/ic_launcher"
        android:visibility="visible" />

    <LinearLayout
        android:id="@+id/rel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:padding="10dp"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/name_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:gravity="center"
            android:text="Product 1"
            android:textColor="@android:color/black"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/txt_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:paddingBottom="10dp"
            android:paddingTop="10dp"
            android:textColor="@android:color/black"
            android:textSize="15sp"
             />
    </LinearLayout>

</LinearLayout>