android:根据服务器响应实现应用搜索建议

时间:2014-01-27 07:47:47

标签: android search android-contentprovider

我需要在我的Android应用程序中构建一个搜索功能,它依赖于服务器的json响应。用户将在位于操作栏中的搜索视图中输入搜索查询。根据用户类型,将对服务器进行查询,并且服务器返回的响应应显示为下拉建议。我应该怎么做呢。根据我读过的文档,我需要实现一个内容提供者。什么是实现应用搜索的最佳方式?

2 个答案:

答案 0 :(得分:9)

请参阅我为EditText实现的以下代码。您也可以执行以下操作:

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();
                }

            }
        }
    });

当用户在EditText中输入第一个字符时,它将调用webService。然后将所有响应保存到tempArray中,当用户输入另一个字符时,它将从tempArray中搜索该元素。 方法startServiceForSearchSuggestion()是:

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);
    }
}

它将启动webservice以从服务器获取响应。 服务类是:

 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方法你必须向你的活动发送广播,并且接收这个broadCast,你可以将你的Json数据保存到arrayList中。就像这样:

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();
            }

        }
    };

方法:

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();
            }


    }

我已经使用Json Object的arrayList设置了适配器,如下所示:

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

    mDListRightOverLap.setAdapter(mOverlapAdapter);

您可以直接将具有指定标记的JSONObject的ArrayList中的数据读入适配器的getView方法。

您需要在Manifest中定义此服务,如下所示:

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

希望它会对你有所帮助。

答案 1 :(得分:2)

您可以为AutoCompleteTextView定制适配器。

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

AutoCompleteAdapter类

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类

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;

}