Два одновременных AsyncTasks в Android - Как справиться с условиями гонки? - PullRequest
2 голосов
/ 14 февраля 2020

Я отправляю сообщение HTTP каждый раз, когда нажимается кнопка, и каждый раз, когда она отпускается. Вероятно, у меня не будет ответа от «нажатой» POST до отпускания кнопки, поэтому я пытаюсь выполнять эти задачи одновременно. Однако иногда POST-запрос на отпускание кнопки отправляется на сервер перед запросом на нажатие кнопки. Как я могу избежать / исправить это?

button = (ImageButton) findViewById((R.id.button1));
        button.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                HTTPAsyncTask task = new HTTPAsyncTask();
                if (event.getAction() == MotionEvent.ACTION_DOWN ) {
                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Utilities.StringCollection.rotateRight);
                    return true;
                }
                else if (event.getAction() == MotionEvent.ACTION_UP){
                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Utilities.StringCollection.stop);
                    return true;
                }
                return false;
            }
        });

Ответы [ 2 ]

0 голосов
/ 14 февраля 2020

Концептуально ваш HTTPAsyncTask doInBackground() состоит из 2 различных действий:

  1. Подключите и поставьте в очередь запрос к сокету
  2. Получите ответ

(после чего, конечно, будет вызываться onPostExecute().)

Как вы уже описали, вам нужно контролировать порядок выполнения для действия # 1 в двух разных потоках, одновременно позволяя параллельное действие № 2.

Это невозможно при использовании механизма generi c AsyncTask, поскольку вы не предоставили никакого способа «разбить задачу на две части»; поток A не может выяснить, когда поток B переключился с действия № 1 на действие № 2 или наоборот.

Возможно, такие логики c могут быть добавлены, но вы не объяснили как вы выполняете вызов сокета.

Однако нет смысла предоставлять эту дополнительную информацию; крайние случаи, связанные с сетевыми запросами, разрушают любую гарантию порядка, который у вас мог быть. Сети с потерями; запросы могут потерпеть неудачу, ответы могут потерпеть неудачу. Запросы могут поступать не в порядке, даже если они были отправлены по порядку (особенно если вы используете два отдельных сокета). Автоматические c повторные попытки могут занять несколько секунд для выполнения sh.

IOW, «нажатый» запрос может быть потерян сетью, и вам, возможно, придется когда-нибудь переместить его в сокет после того, как «неотжатый» запрос завершен.

Я бы посоветовал вам отказаться от «частичного условного параллелизма», к которому вы стремитесь, и просто убедиться, что первый HTTPAsyncTask завершен, прежде чем выполнить второй. .

В качестве альтернативы, вы можете добавить последовательный «идентификатор запроса» к каждому POST или включить информацию о первом запросе в во втором запросе, чтобы сервер мог разобрать, что произошло, даже если запросы поступили не в порядке.

0 голосов
/ 14 февраля 2020

Если ваш минимальный SDK равен 11 «HONEYCOMB», вы можете вызвать asyncTask следующим образом, чтобы запустить его в одном потоке, чтобы предотвратить состояние гонки между ними:

button = (ImageButton) findViewById((R.id.button1));
        button.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                HTTPAsyncTask task = new HTTPAsyncTask();
                if (event.getAction() == MotionEvent.ACTION_DOWN ) {
                    task.execute(Utilities.StringCollection.rotateRight);// using one thread
                    return true;
                }
                else if (event.getAction() == MotionEvent.ACTION_UP){
                    task.execute(Utilities.StringCollection.stop);// using one thread
                    return true;
                }
                return false;
            }
        });

ВАЖНО : сеть I / O не является надежным, и сетевые пакеты могут быть потеряны или не могут быть получены в той последовательности, в которой они были отправлены, но я видел вопрос в заголовке

"Две одновременные AsyncTasks в Android - Как обрабатывать гонки условия? "

и только что ответил. Таким образом, вы не можете быть уверены, что один запрос получен за другим таким образом. Я предлагаю вам отправить два события в одном запросе на сервер и проанализировать его на сервере.

...