android: Implement app search suggestion based on server response
Asked Answered
B

2

12

I need to build a search functionality in my android app which relies on json response from the server. The users will enter the search query in a searchview located in the actionbar. Based on what the user types a query will be made to the server and the server returned response should appear as drop down suggestion. How should I go about it . Based on the docs i have read I need to implement a content provider. What would be neatest way of implementing app search ?

Blaspheme answered 27/1, 2014 at 7:47 Comment(4)
I would suggest using this: https://mcmap.net/q/1010154/-android-how-to-get-search-suggestions-asynchronously-from-the-web or #4265089Proletarian
You can return response from server at one time and hold all data in ArrayList and can do searching in listview From ArrayList. Also you can implement search query to database you are using and can collect return response to arraylist via webservice and can show that in listview.Protrude
You could also use an asynctask but that's not recommended if your call with take more than a few seconds. In short, download and store the result, then present it to the user. This is if your activity gets terminated because the users starts to do other things. When the result is no longer needed, delete it so you don't use up space.Conformable
#8653760Publish
C
11

See the below code I have implemented for EditText.You can also do something like this:

private ArrayList<JSONObject> mRightListOverlapData, mRightTempData;
mEdit_Search.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {


        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            mRightListOverlapData.clear();
            String searchTag = mEdit_Search.getText().toString();
            if (searchTag == null || searchTag.equals("")) {


                mRightTempData.clear();
                mOverlapAdapter.notifyDataSetChanged();

            } else if (searchTag.length() == 1) {

                    mRightListOverlapData.addAll(mRightTempData);



                    mOverlapAdapter.notifyDataSetChanged();
                } else {
                    **startServiceForSearchSuggestion(searchTag);**
                }


            } else {

                try {
                    if (mRightTempData.size() > 0) {

                        for (int i = 0; i < mRightTempData.size(); i++) {
                            if (mRightTempData.get(i)
                                    .getString("search_text").toLowerCase()
                                    .startsWith(searchTag.toLowerCase())) {
                                mRightListOverlapData.add(mRightTempData
                                        .get(i));
                            }
                        }
                        if (mRightListOverlapData.size() == 0) {
                            JSONObject noData = new JSONObject();
                            noData.put("search_text", "No Data");
                            mRightListOverlapData.add(noData);

                        }
                    }

                    mOverlapAdapter.notifyDataSetChanged();
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }
    });

It will call webService when user enters 1st character in EditText.And then save all response into tempArray and when user enters another character it will search that element from tempArray. Method startServiceForSearchSuggestion() is:

private void startServiceForSearchSuggestion(String search_tag) {
    if (!Utils.isNetworkAvailable(getBaseContext())) {
        Toast.makeText(getBaseContext(), "No Network Available",
                Toast.LENGTH_SHORT).show();
    } else {
        Intent intent1 = new Intent(this, WebService.class);
        intent1.putExtra(METHOD, GET_SEARCH_SUGGESTION);
        intent1.putExtra("search_tag", search_tag);
        startService(intent1);
    }
}

It will start webservice to get response from server. The service class is:

 public class WebService extends Service implements WebServiceConstants {
    private AppPreferences mPrefs;
    private static String TAG_WEB_SERVICE = "WebService";
    private static String DEVICE_TYPE = "android";
    private static String MESSAGE_CENTER = "gcm";
    private static String URL_JSON = "YOUR_URL";
    private Context mContext;
    private int METHOD_NAME = 1;
    private String mSearch_Tag = "";
    private DBQuery mDBQuery;
    public static boolean is_Service_Running = false;

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        mContext = this;
        mPrefs = new AppPreferences(mContext);
        mDBQuery = new DBQuery(mContext);

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        try {
            METHOD_NAME = intent.getIntExtra(METHOD, 1);

                mSearch_Tag = intent.getStringExtra("search_tag");

            LoadDataFromServer data = new LoadDataFromServer();
            data.execute();
        } catch (NullPointerException e) {
            // TODO: handle exception
        }
        super.onStart(intent, startId);
    }

public class LoadDataFromServer extends AsyncTask<Void, Void, Void> {
        JSONObject response;

        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub
            JSONObject root = getJsonHeader();
            switch (METHOD_NAME) {


            case GET_SEARCH_SUGGESTION:
                response = getResponse(yourJsonRequestObject);
                break;

            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            try {

                switch (METHOD_NAME) {


                case GET_SEARCH_SUGGESTION:
                    Log.v(TAG_WEB_SERVICE,
                            "Response = GET_SEARCH_SUGGESTION : "
                                    + response.toString());
                    sendBroadcast(new Intent(METHOD_GET_SEARCH_SUGGESTION)
                            .putExtra("Response", response.toString()));

                    break;

                default:
                    break;
                }
            } catch (NullPointerException e) {
                // TODO: handle exception
            }

        }

    }
    }

onPostExecute method you have to send broadcast to your activity and onReceive of this broadCast you can save your Json data into arrayList.Like this:

private BroadcastReceiver mReceiverSearchSuggestion = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            JSONObject root;
            try {
                root = new JSONObject(intent.getStringExtra("Response"));
                setSearchSuggestions(root);
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    };

Methods:

1.

private JSONObject getResponse(JSONObject obj) {
        // Create a new HttpClient and Post Header
        HttpClient httpclient = new DefaultHttpClient();
        HttpParams myParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(myParams, 10000);
        HttpConnectionParams.setSoTimeout(myParams, 10000);
        String temp = "";

        try {

            HttpPost httppost = new HttpPost(URL_JSON);
            httppost.setHeader("Content-type", "application/json");
            StringEntity se = new StringEntity(obj.toString());
            se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
                    "application/json"));
            httppost.setEntity(se);

            HttpResponse response = httpclient.execute(httppost);
            temp = EntityUtils.toString(response.getEntity());
            Log.v(TAG_WEB_SERVICE, "Temp = " + temp);
            if (temp == null || temp.trim().equals("")) {

            } else {
                return new JSONObject(temp);
            }
        } catch (ClientProtocolException e) {

        } catch (IOException e) {

        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

2.

private void setSearchSuggestions(JSONObject root) {
        // TODO Auto-generated method stub
        try {
            JSONObject search_suggestion = root
                    .getJSONObject(METHOD_GET_SEARCH_SUGGESTION);
            if (search_suggestion.getString("response_type").equalsIgnoreCase(
                    "success")) {
                if (search_suggestion.has("data")) {
                    mRightTempData.clear();
                    mRightListOverlapData.clear();
                    JSONArray data = search_suggestion.getJSONArray("data");
                    for (int i = 0; i < data.length(); i++) {
                        JSONObject value = data.getJSONObject(i);

                        mRightTempData.add(value);
                    }

                } else {
                    Toast.makeText(getBaseContext(),
                            "No data related to search", Toast.LENGTH_SHORT)
                            .show();
                }
            } else {
                Toast.makeText(getBaseContext(),
                        "Search Suggestion : Type Failure", Toast.LENGTH_SHORT)
                        .show();
            }


    }

I have set adapter with arrayList of Json Object like this:

        mOverlapAdapter = new RightOverlapAdapter(getBaseContext(),
            mRightListOverlapData);

    mDListRightOverLap.setAdapter(mOverlapAdapter);

You can directly read data from ArrayList of JSONObject with specified tag into getView method of your adapter.

You need define this service in Manifest like this:

 <service android:name="com.your.package.WebService" />

Hope it will help you.

Counterattraction answered 25/2, 2014 at 9:17 Comment(0)
B
2

You can just customize the adapter for AutoCompleteTextView.

...
getInput = (AutoCompleteTextView) rootView
                .findViewById(R.id.translate_word);
getInput.setAdapter(new AutoCompleteAdapter(mContext));
...

AutoCompleteAdapter Class

public class AutoCompleteAdapter extends ArrayAdapter<AutoCompleteItem> {

    protected static final String TAG = "AutoCompleteAdapter";
    private Context mContext; 
    private LayoutInflater vi; 
    private List<AutoCompleteItem> suggestions;

    public AutoCompleteAdapter(Context context) {
        super(context, R.layout.autocomplete_item);
        this.mContext = context;
        vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        suggestions = new ArrayList<AutoCompleteItem>();
    }

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

    @Override
    public AutoCompleteItem getItem(int index) {
        return suggestions.get(index);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView; 
        final AutoCompleteItem i = suggestions.get(position); 
        if (i != null) {
            AutoCompleteItem aci = (AutoCompleteItem)i; 
            v = vi.inflate(R.layout.autocomplete_item, null); 
            final TextView txtWord = (TextView)v.findViewById(R.id.word);
            if (txtWord != null) { 
                txtWord.setText(aci.getWord());
            }

            final TextView txtLang = (TextView)v.findViewById(R.id.lang);
            if (txtLang != null) {
                if (aci.getLang() != null && !aci.getLang().equals(""))
                    txtLang.setText("[" + aci.getLang().toUpperCase() + "]");
            }

            final TextView txtConj = (TextView)v.findViewById(R.id.conj);
            if (txtConj != null) { 
                txtConj.setText(aci.getConj());
                txtConj.setTag(i); 

                txtConj.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        AutoCompleteItem autoCompleteItem = (AutoCompleteItem)v.getTag(); 
                        String lang = autoCompleteItem.getLang(); 
                        // v.getParent().
                        String word = autoCompleteItem.getWord(); 

                    }
                }); 
            }
        }
        return v; 
    }


    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null && !constraint.toString().equalsIgnoreCase(sWord) && constraint.toString().length() >= 2) {
                    AutoCompleteParse acp = new AutoCompleteParse();
                    // A class that queries a web API, parses the data and
                    // returns an ArrayList<AutoCompleteItem>
                    List<AutoCompleteItem> new_suggestions =acp.getAutoComplete(mContext, constraint.toString());
                    suggestions.clear();
                    for (int i=0;i<new_suggestions.size();i++) {
                        suggestions.add(new_suggestions.get(i));
                    }

                    if (suggestions.size() > 0) sWord = constraint.toString(); 
                    // Now assign the values and count to the FilterResults
                    // object
                    filterResults.values = suggestions;
                    filterResults.count = suggestions.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint,
                    FilterResults results) {
                if (contraint != null && !contraint.toString().equalsIgnoreCase(sWord) && contraint.toString().length() >= 2 
                        && results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }
}

AutoCompleteParse Class

public class AutoCompleteParse {

Context mContext; 

public AutoCompleteParse() {
}

public List<AutoCompleteItem> getAutoComplete(Context context, String sWord) {
    this.mContext = context;


    ...
    List<AutoCompleteItem> ListData = new ArrayList<AutoCompleteItem>();
    try {
        URL acUrl = new URL(autoCompleteUrl);
        URLConnection acConn = acUrl.openConnection();
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                acConn.getInputStream()));

        String line = reader.readLine();
        do {
        ...
        } while (line != null);

    } catch (Exception e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    return ListData;

}
Bunce answered 4/3, 2014 at 5:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.