Автоматический поиск по типам пользователей - PullRequest
7 голосов
/ 18 мая 2011

У меня есть действие, когда пользователь вводит текст EditText, нажимает кнопку поиска, и приложение запрашивает веб-службу и помещает результаты в ListView.

Я бы хотел покончить с кнопкой поиска.

Очевидно, я не хочу, чтобы каждый символ, который пользователь вводит, попадал в веб-сервис. Я хочу выполнить только 1 вызов веб-службы, когда пользователь закончит ввод.

То, как я этого добиваюсь, выглядит так:

У меня есть переменная-член, которая содержит AsyncTask. Когда текст в EditText изменяется, AsyncTask срабатывает. Внутри doInBackground () происходит вызов Thread.sleep (). Этот период ожидания по сути является таймером, ожидающим, чтобы увидеть, печатает ли пользователь что-либо еще. После неактивного вызова выполняется вызов веб-службы, если AsyncTask не был отменен. Если пользователь вводит другую букву, на AsyncTask вызывается метод cancel () (чтобы запретить вызов веб-службы), переменной-члену, содержащей AsyncTask, присваивается значение NULL, и создается новый экземпляр AsyncTask.

У меня есть несколько вопросов: у меня течет память? Это особенно плохо в любом случае? Я понимаю, что это может быть не самым эффективным, но я собираюсь серьезно замедлить чей-то телефон? Есть ли лучший способ сделать это?

private SearchTask mSearchTask = null;

...

    mSearchText.addTextChangedListener(new TextWatcher() {

        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // Auto-generated method stub
        }

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

        public void afterTextChanged(Editable s) {
                if (s != null && s.length() > 0) {
                    // stop any current search thread
                    if (mSearchTask != null && !mSearchTask.isCancelled()) {
                        mSearchTask.cancel(false);
                    }


                        // search for products
                        SearchCriteria crit = new SearchCriteria();
                        crit.strSearchWord = mSearchText.getText().toString().trim();
                        mSearchTask = null;
                        mSearchTask = new SearchTask();
                        mSearchTask.execute(crit);
                }
        }
    });

...

private class SearchTask extends AsyncTask<SearchCriteria, Integer, Boolean> {
    protected Boolean doInBackground(SearchCriteria... params) {
        SearchCriteria crit = null;
        if (params.length > 0) {
            crit = params[0];

            if (crit != null) {
                try {
                    Thread.sleep(1000L);
                    if (!isCancelled()) {
                        // perform search
                        return true;
                    }
                }
                catch(Exception e) {
                }
            }
        }

        return false;
    }

    protected void onPostExecute(Boolean success) {
        if (success != null && success == true) {
            // do something
        }
        else {
            // do something else
        }
    }   
}

Ответы [ 4 ]

9 голосов
/ 23 мая 2011

У меня было бы больше соблазна запустить поток за x миллисекунд и затем выполнить проверку, в отличие от немедленного запуска потока со сном.

private Handler mMessageHandler = new Handler();

private Runnable mSearchRunnable = new Runnable() {
        public void run() {
           if (!isCancelled()) {
               // perform search
           }
        }
    };

тогда вы можете положить это в вас afterTextChanged:

mMessageHandler.postDelayed(mSearchRunnable, 1000);

Вы можете отменить поток, если пользователь вводит больше данных с помощью:

 mMessageHandler.removeCallbacks(mSearchRunnable);
3 голосов
/ 29 мая 2011

Вам следует подумать о вызове отмены (true), чтобы попытаться завершить задачу, когда она находится в ожидании или если вызов на веб-сервер уже выполняется. Это может сэкономить вам некоторые циклы процесса, чтобы ваш веб-сервер мог не беспокоиться о прерванных вызовах.

Если вы хотите сохранить некоторые циклы gc, вы можете использовать объект SearchCriteria повторно, если это возможно.

Кроме этого, я не вижу утечек памяти. У ваших объектов короткий жизненный цикл, и вы их не кэшируете. Единственная проблема, которая может возникнуть - слишком много параллельных AsyncTasks с запущенными http-запросами, что приведет к преждевременному нехватке памяти. Однажды у нас была эта проблема с одним приложением во время теста на обезьяну.

2 голосов
/ 24 мая 2011

привет, это ссылка, которая может вам помочь ..

http://thinkandroid.wordpress.com/2010/02/08/writing-your-own-autocompletetextview/

0 голосов
/ 30 мая 2011
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    lv1 = (ListView) findViewById(R.id.ListView01);
    ed = (AutoCompleteTextView) findViewById(R.id.EditTextSearch);

    // AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, R.layout.list_item, countryName);
        ed.setAdapter(adapter1);

    this.getWindow().setSoftInputMode(
            WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    final List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
    for (int i = 0; i < countryName.length; i++) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("flag", "" + imageId[i]);
        map.put("country", countryName[i].toString());
        map.put("capital", capitalName[i].toString());
        map.put("countrytime",
                convertDateTimeToGMT(GMTplusMinusInMillisecond[i],
                        plusMinus[i]));
        map.put("GMT", GMTplusMinus[i].toString());

        fillMaps.add(map);
    }

    // fill in the grid_item layout
    SimpleAdapter adapter = new SimpleAdapter(this, fillMaps,
            R.layout.grid_item, from, to);
    lv1.setAdapter(adapter);

    ed.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            fillMaps.clear();
            textlength = ed.getText().length();
            for (int i = 0; i < countryName.length; i++) {
                if (textlength <= countryName[i].length()) {
                    if (ed.getText()
                            .toString()
                            .equalsIgnoreCase(
                                    (String) countryName[i].subSequence(0,
                                            textlength))) {
                        HashMap<String, String> map = new HashMap<String, String>();
                        map.put("flag", "" + imageId[i]);
                        map.put("country", countryName[i].toString());
                        map.put("capital", capitalName[i].toString());
                        map.put("countrytime",
                                convertDateTimeToGMT(
                                        GMTplusMinusInMillisecond[i],
                                        plusMinus[i]));
                        map.put("GMT", GMTplusMinus[i].toString());

                        fillMaps.add(map);
                    }
                }
            }
            if(!fillMaps.isEmpty())
            {
            SimpleAdapter adapter = new SimpleAdapter(
                    WorldClockActivity.this, fillMaps, R.layout.grid_item,
                    from, to);
            lv1.setAdapter(adapter);
            }
            else
            {      String[] COUNTRIES = new String[] {"No record found"};
            lv1.setAdapter(new ArrayAdapter<String>(WorldClockActivity.this,R.layout.list_item, COUNTRIES));
            }

            // lv1.setAdapter(new
            // ArrayAdapter<String>(WorldClockActivity.this,android.R.layout.simple_list_item_1
            // , arr_sort));

        }
    });
}

public static String convertDateTimeToGMT(long millis, int plusMinus) {

    Calendar CalGMT;
    TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
    CalGMT = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
    CalGMT.get(Calendar.DAY_OF_MONTH);
    CalGMT.get(Calendar.MONTH);
    CalGMT.get(Calendar.YEAR);
    CalGMT.get(Calendar.HOUR_OF_DAY);
    CalGMT.get(Calendar.MINUTE);
    CalGMT.get(Calendar.SECOND);

    if (plusMinus == 1) {
        CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() + millis);
    } else if (plusMinus == 0) {
        CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() - millis);
    }
    String sendDateTimeInGMT = CalGMT.get(Calendar.HOUR_OF_DAY) + ":"
            + CalGMT.get(Calendar.MINUTE) + ":"
            + CalGMT.get(Calendar.SECOND);

    return sendDateTimeInGMT;
}

}

Я сделал приложение, используя приведенный выше код в этом приложении. Я использую AutoCompleteTextView для предоставления возможности поиска в виде списка, затем в виде списка отображается название всей страны и пользователь, который можетПоиск страны по названию страны, когда пользователь вводит в AutoCompleteTextView, то соответствующий поиск отображается в виде списка.Например, если пользователь хочет найти Канаду в списке стран мира, тогда пользователь только набирает ca в AutoCompleteTextView, затем появляется другой список, который выдает AutoCompleteTextView и показывает начальное имя всей страны с именем, после чего пользователь выбрал Канаду в этом спискезатем получите всю информацию о Канаде в виде списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...