【问题标题】:android: Implement app search suggestion based on server responseandroid:根据服务器响应实现应用搜索建议
【发布时间】:2014-02-17 23:19:58
【问题描述】:

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

【问题讨论】:

  • 您可以一次从服务器返回响应并将所有数据保存在 ArrayList 中,并且可以从 ArrayList 中在 listview 中进行搜索。您还可以对正在使用的数据库实施搜索查询,并可以通过 web 服务收集对 arraylist 的返回响应,并可以在 listview 中显示。
  • 您也可以使用异步任务,但如果您的通话时间超过几秒钟,则不建议这样做。简而言之,下载并存储结果,然后将其呈现给用户。这是如果您的活动因用户开始做其他事情而终止。当不再需要结果时,将其删除,以免占用空间。

标签: android search android-contentprovider


【解决方案1】:

请参阅我为 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);
    }
}

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

 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 方法,您必须向您的活动发送广播,并且您可以在此广播的 onReceive 中将您的 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 对象的 arrayList 设置了适配器,如下所示:

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

    mDListRightOverLap.setAdapter(mOverlapAdapter);

您可以直接从带有指定标签的JSONObject的ArrayList中读取数据到您的适配器的getView方法中。

你需要像这样在 Manifest 中定义这个服务:

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

希望对你有所帮助。

【讨论】:

    【解决方案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;
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      相关资源
      最近更新 更多