#java #android #sockets #android-asynctask
#java #Android #сокеты #android-asynctask
Вопрос:
Я сталкиваюсь с проблемой при попытке отправить «сигнал» моему AsyncTask
классу, чтобы остановить выполнение и закрыть соединение с сокетом. В doInBackground
способе я настраиваю соединение с сокетом, отправляю первый пакет полезной нагрузки и ожидаю входящих пакетов:
mRunning = true;
try {
byte[] data = null;
mSocket = mTlsSocketFactory.createSocket(mTlsSocketFactory.getServerAddress(), mTlsSocketFactory.getServerPort());
LogHelper.printLogMsg("INFO socket created");
out = new DataOutputStream(mSocket.getOutputStream());
out.flush();
inStream = new DataInputStream(mSocket.getInputStream());
//send authenticate payload
requestSendPayload(authenticatePayload, params);
while (mRunning) {
int type = inStream.readInt();
type = Integer.reverseBytes(type);
mResID = type;
int length = inStream.readInt();
length = Integer.reverseBytes(length);
if (length > 0) {
data = new byte[length];
inStream.readFully(data);
publishProgress(data);
}
data = null;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) out.close();
if (inStream != null) inStream.close();
if (mSocket != null) mSocket.close();
} catch (IOException e) {
e.fillInStackTrace();
}
}
Когда я получаю пакет, который я хочу, я должен закрыть соединение. У меня есть открытый метод внутри AsyncTask
класса:
public void close() {
mRunning = false;
}
Но проблема в том, что блок ‘while’ никогда не заканчивается и doInBackground
никогда не завершался.
Есть много сообщений с подобной проблемой, но я пытался вызвать cancel (true) на моем, AsyncTask
но без результата — doInBackground
так и не закончил. Мой вопрос в том, как отправить ‘signal’ в doInBackground
метод, чтобы мой цикл while мог завершиться?
Я могу переписать closeMethod на что-то вроде этого:
new Thread(new Runnable() {
@Override
public void run() {
try {
if (out != null) out.close();
if (inStream != null) inStream.close();
if (mSocket != null) mSocket.close();
} catch (IOException e) {
e.fillInStackTrace();
}
}
}).start();
И после этого я перехватываю исключение при попытке прочитать: DataInputStream.readInt()
а затем doInBackground
завершится. Но я не уверен, что это правильное решение.
Ответ №1:
Вы должны реализовать onCancelled в своем методе async task
@Override
protected void onCancelled() {
mRunning = false;
}
после этого вы просто вызываете
mySocketAsyncTaskObject.cancel(false);
Другим вариантом было бы удалить ваше свойство mRunning и переопределить onCancelled и просто проверить наличие isCancelled()
while (!IsCancelled()) {
int type = inStream.readInt();
type = Integer.reverseBytes(type);
mResID = type;
int length = inStream.readInt();
length = Integer.reverseBytes(length);
if (length > 0) {
data = new byte[length];
inStream.readFully(data);
publishProgress(data);
}
data = null;
}
В качестве личного замечания я хочу добавить, что хорошей практикой является использование класса Service для инкапсуляции функциональности вашего сокета и использования простого объекта Thread, а не AsyncTask
Комментарии:
1. Спасибо за ответ, но первое решение не работает, потому что onCancelled никогда не вызывается. Из документации: «Вызов метода cancel() приведет к вызову onCancelled(Object) в потоке пользовательского интерфейса после возврата doInBackground(Object[])». Мой doInBackground никогда не заканчивается, поэтому onCancelled не вызывается. Я пробовал со вторым решением, но, похоже, это тоже не работает — я вызываю: myAsyncTaskObj.cancel(true); но doInBackground так и не был завершен. И да, я читал, что класс AsyncTask не такое уж хорошее решение, и, возможно, я подумываю о повторной реализации этого.
2. попробуйте передать false в метод cancel, таким образом, поток не будет прерван, и isCancelled() должен вернуть true
3. Нет, к сожалению, ничего не происходит.