Как разблокировать InputStream.read () на Android? - PullRequest
7 голосов
/ 05 июля 2011

У меня есть поток, в котором read() метод InputStream вызывается в цикле.Если больше нет байтов для чтения, поток будет блокироваться до тех пор, пока не поступят новые данные.

Если я вызову close() на InputStream из другого потока, поток закроется, но заблокируется read() звонок по-прежнему остается заблокированным.Я бы предположил, что метод read() теперь должен возвращать со значением -1, чтобы указать конец потока, но это не так.Вместо этого он остается заблокированным еще несколько минут, пока не истечет время ожидания tcp.

Как разблокировать вызов close()?

Редактировать:

Очевидно, что обычная JRE немедленно выдаст SocketException, когда поток или сокет, которому соответствует блокирующий вызов read(), равен close() 'd.Однако среда выполнения Android Java, которую я использую, не будет.

Будем весьма благодарны за любые подсказки относительно решения для среды Android.

Ответы [ 6 ]

4 голосов
/ 05 июля 2011

Вызывать read() можно только при наличии доступных данных.

Сделайте что-то подобное:

    while( flagBlock )
    {
        if( stream.available() > 0 )
        {
            stream.read( byteArray );
        }
    }

установите flagBlock, чтобы остановить чтение.

3 голосов
/ 05 июля 2011

См. Параллелизм Java на практике для действительно хорошей системы для отмены потока при работе с сокетами.Он использует специальный исполнитель (CancellingExecutor) и специальный Callable (SocketUsingTask).

3 голосов
/ 05 июля 2011

Когда другой конец закроет соединение, ваш поток вернет -1 при чтении (). Если вы не можете запустить другой конец, чтобы закрыть соединение, например, закрыв ваш выходной поток, вы можете закрыть сокет, который вызовет IOException в блокирующем потоке read ().


Можете ли вы привести краткий пример, который воспроизводит вашу проблему?

ServerSocket ss = new ServerSocket(0);
final Socket client = new Socket("localhost", ss.getLocalPort());
Socket server = ss.accept();
Thread t = new Thread(new Runnable() {
    public void run() {
        int ch;
        try {
            while ((ch = client.getInputStream().read()) != -1)
                System.out.println(ch);
        } catch (SocketException se) {
            System.out.println(se);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});
t.start();
server.getOutputStream().write("hi\n".getBytes());
Thread.sleep(100);
client.close();
t.join();

server.close();
ss.close();

печать

104
105
10
java.net.SocketException: Socket closed
2 голосов
/ 05 января 2012

У нас возникла та же проблема: не исключение при переключении сети (например, переключение с 3G на WiFi во время загрузки).

Мы используем код из http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification,, который работает отлично, за исключением некоторых случаев, когда сетевое соединение было потеряно.

В решении было указано значение тайм-аута, для него установлено стандартное значение 0 (что означает: ждать бесконечно).

    HttpURLConnection c = (HttpURLConnection) u.openConnection();
    c.setRequestMethod("GET");
    c.setDoOutput(true);
    c.setReadTimeout(1000);
    c.connect();

Поэкспериментируйте с подходящим для вас значением времени ожидания.

1 голос
/ 23 июля 2014

У меня была такая проблема на Samsung 2.3.При переключении с 3G на Wifi блоки метода InputStream.read ().Я перепробовал все советы из этой темы.Ничего не помоглоС моей точки зрения, это проблема конкретного устройства, потому что должно вызвать IOException из-за javadoc .Мое решение состоит в том, чтобы прослушать трансляцию Android android.net.conn.CONNECTIVITY_CHANGE и закрыть соединение с другим потоком, это вызовет IOException в заблокированном потоке.

Вот пример кода:

DownloadThread.java

private volatile boolean canceled;

private volatile InputStream in;

private boolean downloadFile(final File file, final URL url, long totalSize) {
    OutputStream out = null;
    try {
        Log.v(Common.TAG, "DownloadThread: downloading to " + file);

        in = (InputStream) url.getContent();
        out = new FileOutputStream(file);

        return copy(out, totalSize);
    } catch (Exception e) {
        Log.e(Common.TAG, "DownloadThread: Exception while downloading. Returning false ", e);
        return false;
    } finally {
        closeStream(in);
        closeStream(out);
    }
}

public void cancelDownloading() {
    Log.e(Common.TAG, "DownloadThread: cancelDownloading ");
    canceled = true;
    closeStream(in); //on my device this is the only way to unblock thread
}

private boolean copy(final OutputStream out, long totalSize) throws IOException {
    final int BUFFER_LENGTH = 1024;
    final byte[] buffer = new byte[BUFFER_LENGTH];
    long totalRead = 0;
    int progress = 0;
    int read;

    while (!canceled && (read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
        totalRead += read;
    }
    return !canceled;
}
1 голос
/ 05 июля 2011

Вы можете использовать java.nio пакет.NIO расшифровывается как неблокирующий ввод-вывод.Здесь звонки (например, чтение и запись) не блокируются.Таким образом, вы можете закрыть поток.

Существует пример программы, которую вы можете посмотреть на здесь .Метод: processRead

...