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

时间:2011-07-05 08:00:43

标签: java android sockets inputstream

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

如果我从其他主题调用close()上的InputStream,则会关闭该流,但阻止的read()来电仍会被阻止。我假设read()方法现在应返回值为-1以指示流的结束,但事实并非如此。相反,它会被阻塞几分钟,直到发生tcp超时。

如何取消阻止close()来电?

修改

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

非常感谢任何关于Android环境解决方案的提示。

6 个答案:

答案 0 :(得分:4)

只有有可用数据时才调用read()

做类似的事情:

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

设置flagBlock以停止阅读。

答案 1 :(得分:3)

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


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

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 :(得分:3)

在使用套接字时,请参阅Java Concurrency In Practice以获得一个非常好的系统来取消线程。它使用特殊的执行器(CancellingExecutor)和特殊的Callable(SocketUsingTask)。

答案 3 :(得分:2)

我们遇到了同样的问题:切换网络时也不例外(例如,在下载时从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();

尝试适合您的超时值。

答案 4 :(得分:1)

您可以使用java.nio包。 NIO代表非阻塞IO。这里的呼叫(称为读和写)不会被阻止。这样你就可以关闭流了。

您可以查看here示例程序。方法:processRead

答案 5 :(得分:1)

我在三星2.3上遇到过这样的问题。从3G切换到Wifi InputStream.read()方法块时。我尝试了这个主题的所有提示。什么都没有帮助。从我的角度来看,这是特定于设备的问题,因为应该javadoc而抛出IOException。我的解决方案是侦听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;
}