java 如何在 Android 上解锁 InputStream.read()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6579539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:27:55  来源:igfitidea点击:

How to unblock InputStream.read() on Android?

javaandroidsocketsinputstream

提问by tajmahal

I have a thread in which the read()method of an InputStreamis called in a loop. When there are no more bytes to read, the stream will block until new data arrives.

我有一个线程,其中在循环中调用read()an的方法InputStream。当没有更多字节要读取时,流将阻塞,直到新数据到达。

If I call close()on the InputStreamfrom a different thread, the stream gets closed, but the blocked read()call still remains blocked. I would assume that the read()method should now return with a value of -1to indicate the end of the stream, but it does not. Instead, it stays blocked for several more minutes until a tcp timeout occurs.

如果我呼吁close()InputStream从不同的线程,流被关闭,但被阻止的read()电话仍然受阻。我假设该read()方法现在应该返回一个值-1来指示流的结束,但事实并非如此。相反,它会继续阻塞几分钟,直到发生 tcp 超时。

How do I unblock the close()call?

如何取消阻止close()呼叫?

Edit:

编辑:

Apparently, the regular JRE will throw a SocketExceptionimmediately when the stream or socket the blocking read()call corresponds to is close()'d. The Android Java runtime which I am using, however, will not.

显然,SocketException当阻塞read()调用对应的流或套接字为close()'d时,常规 JRE 将立即抛出 a 。但是,我使用的 Android Java 运行时不会。

Any hints on a solution for the Android environment would be greatly appreciated.

任何有关 Android 环境解决方案的提示将不胜感激。

采纳答案by Talha Ahmed Khan

Only call read()when there is data available.

read()在有可用数据时调用。

Do something like that:

做这样的事情:

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

set the flagBlockto stop the reading.

设置flagBlock停止阅读。

回答by Peter Lawrey

When the other end closes the connection your stream will return -1 on a read(). If you cannot trigger the other end to close the connection e.g. by closing your output stream, you can close the socket which will cause an IOException in the blocking read() thread.

当另一端关闭连接时,您的流将在 read() 上返回 -1。如果您无法触发另一端关闭连接,例如通过关闭输出流,您可以关闭套接字,这将导致阻塞 read() 线程中的 IOException。



Can you provide a short example which reproduces your problem?

你能提供一个简短的例子来重现你的问题吗?

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();

prints

印刷

104
105
10
java.net.SocketException: Socket closed

回答by Wim Deblauwe

See Java Concurrency In Practicefor a really good system to cancel a thread when working with sockets. It uses a special executor (CancellingExecutor) and a special Callable (SocketUsingTask).

有关使用套接字时取消线程的非常好的系统,请参阅Java Concurrency In Practice。它使用一个特殊的 executor ( CancellingExecutor) 和一个特殊的 Callable ( SocketUsingTask)。

回答by MrAppiness

We were having the same issue: no exception when switching network (e.g. switching from 3G to WiFi while downloading).

我们遇到了同样的问题:切换网络时也不例外(例如在下载时从 3G 切换到 WiFi)。

We are using the code from http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification, which is working perfectly except in some cases when the network connection was lost.

我们正在使用来自http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification的代码,除了在某些情况下网络连接丢失外,它运行良好。

The solution was specifying a timeout value, this is set standard to 0 (meaning: wait infinitely).

解决方案是指定超时值,将其标准设置为 0(意思是:无限等待)。

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

Experiment with a timeout value appropriate for you.

试验适合您的超时值。

回答by Pavel Polushkin

I had such issue on Samsung 2.3. When switching from 3G to Wifi InputStream.read() method blocks. I tried all tips from this topic. Nothing helped. From my prospective this is device specific issue because it shouldthrow IOException due to javadoc. My solution is to listen for android broadcast android.net.conn.CONNECTIVITY_CHANGEand close connection from another thread it will cause IOException in blocked thread.

我在三星 2.3 上遇到过这样的问题。当从 3G 切换到 Wifi InputStream.read() 方法块时。我尝试了这个主题的所有提示。没有任何帮助。从我的角度来看,这是设备特定的问题,因为它应该由于javadoc抛出 IOException 。我的解决方案是监听 android 广播android.net.conn.CONNECTIVITY_CHANGE并关闭来自另一个线程的连接,这将导致阻塞线程中的 IOException。

Here is code example:

这是代码示例:

DownloadThread.java

下载线程.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;
}

回答by Anantha Sharma

You could use java.niopackage. NIO stands for Non-blocking IO. Here the calls (to say read & write) aren't blocked. This way you can close the stream.

你可以使用java.nio包。NIO 代表非阻塞 IO。这里的调用(说读和写)没有被阻止。这样你就可以关闭流。

There is a sample program you can look at here. Method: processRead

您可以在此处查看示例程序。方法:processRead