簡體   English   中英

只要其中有內容(Android / Java),如何繼續從InputStream讀取?

[英]How to keep reading from an InputStream as long as there is something in it (Android/Java)?

我正在使用REST API從硬件鍵盤獲取輸入。 我想知道如何在有輸入的情況下繼續從InputStream讀取內容,然后優雅地停止而不拋出SocketTimoutException

我的密碼

// Start a new thread for reading the keyboard input
new Thread(new Runnable() {
    @Override
    public void run() {

        InputStream inputStream = null;
        try {

            // Set byte stream from response body
            inputStream = response.body().byteStream();

            // I THINK THIS IS THE PROBLEM. WHILE (TRUE) //
            while (true) {

                // This is where the rest response is read into an array of bytes. I interpret this array below and it seems to work as intended.
                final byte[] buffer = new byte[256];
                int bytesRead = inputStream.read(buffer, 0, buffer.length);

                // This was more for debugging purposes... it never get invoked, as far as I can tell.
                if (bytesRead < 0) {
                    Log.w(TAG, "...Returning. 0 bytes read.");
                    return;
                }

                // I'll specify what a response looks like below this code block.
                String fullResponse = new String(buffer, StandardCharsets.UTF_8);
                Log.v(TAG, "...Full rest response : \n " + fullResponse);

                // This processes the response, narrowing down to just the keycode. This works as it's supposed to.
                processResponse(fullResponse);

            }

        } catch (IOException e) {
            e.printStackTrace();
            Log.v(TAG, "...Problem reading input stream");

        } finally {

            // Close input stream when I'm done with it.
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}).start();

因此,這是我從其余api得到的響應的示例。 我的processResponse()方法使用按下的鍵碼(在本例中為34)定位並更新文本視圖。 這按預期工作。

...Full rest response : 

timeout: 2000000                                                              
event: keypress                                                                    
id: 1492005344                                                                      
data: {"device":"keyboard","pressedKeycodes":"34 "}

我想知道的是,只要有東西存在,如何繼續從InputStream讀取數據,並且在沒有收到更多輸入而又不拋出SockoutTimeoutException情況下停止SockoutTimeoutException 如果我while(true)不這樣做,則不會出現異常,但它只會讀取一個按鍵。

這是例外:

04-12 15:18:02.467 7585-7810/com.accutime.restpractice W/System.err: java.net.SocketTimeoutException
04-12 15:18:02.469 7585-7810/com.accutime.restpractice W/System.err:     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
04-12 15:18:02.470 7585-7810/com.accutime.restpractice W/System.err:     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
04-12 15:18:02.471 7585-7810/com.accutime.restpractice W/System.err:     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
04-12 15:18:02.472 7585-7810/com.accutime.restpractice W/System.err:     at okio.Okio$2.read(Okio.java:140)
04-12 15:18:02.473 7585-7810/com.accutime.restpractice W/System.err:     at okio.AsyncTimeout$2.read(AsyncTimeout.java:238)
04-12 15:18:02.474 7585-7810/com.accutime.restpractice W/System.err:     at okio.RealBufferedSource.request(RealBufferedSource.java:66)
04-12 15:18:02.475 7585-7810/com.accutime.restpractice W/System.err:     at okio.RealBufferedSource.require(RealBufferedSource.java:59)
04-12 15:18:02.476 7585-7810/com.accutime.restpractice W/System.err:     at okio.RealBufferedSource.readHexadecimalUnsignedLong(RealBufferedSource.java:284)
04-12 15:18:02.477 7585-7810/com.accutime.restpractice W/System.err:     at okhttp3.internal.http.Http1xStream$ChunkedSource.readChunkSize(Http1xStream.java:441)
04-12 15:18:02.478 7585-7810/com.accutime.restpractice W/System.err:     at okhttp3.internal.http.Http1xStream$ChunkedSource.read(Http1xStream.java:422)
04-12 15:18:02.479 7585-7810/com.accutime.restpractice W/System.err:     at okio.RealBufferedSource.read(RealBufferedSource.java:45)
04-12 15:18:02.479 7585-7810/com.accutime.restpractice W/System.err:     at okio.ForwardingSource.read(ForwardingSource.java:35)
04-12 15:18:02.480 7585-7810/com.accutime.restpractice W/System.err:     at retrofit2.OkHttpCall$ExceptionCatchingRequestBody$1.read(OkHttpCall.java:279)
04-12 15:18:02.481 7585-7810/com.accutime.restpractice W/System.err:     at okio.RealBufferedSource$1.read(RealBufferedSource.java:386)
04-12 15:18:02.482 7585-7810/com.accutime.restpractice W/System.err:     at com.accutime.restpractice.MainActivity$1$1.run(MainActivity.java:172)
04-12 15:18:02.483 7585-7810/com.accutime.restpractice W/System.err:     at java.lang.Thread.run(Thread.java:818)

首先,我將創建一個實用程序類,該實用程序類讀取InputStream並返回已讀取內容的byte[] 假設在此示例中,實用程序類稱為InputOutputStreams

我的方法將是:

public static byte[] readFully(InputStream input) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[256];
    int totalBytesRead = 0;
    int bytesRead = 0;

    while (input.read(buffer) > 0) {
        baos.write(buffer, 0, bytesRead);
    }

    return baos.toByteArray();
}

然后,我將刪除您擁有的while循環(以及各種實現),並使用上面實現的實用工具類來檢索InputStream的內容,如下所示:

    // Start a new thread for reading the keyboard input
            new Thread(new Runnable() {
                @Override
                public void run() {

                    InputStream inputStream = null;
                    try {

                        // Set byte stream from response body
                        inputStream = response.body().byteStream();

                            // I'll specify what a response looks like below this code block.
                            //THIS IS WHERE I USE THE UTILITY CLASS
                            String fullResponse = new String(InputOutputStreams.readFully(inputStream), StandardCharsets.UTF_8);
                            Log.v(TAG, "...Full rest response : \n " + fullResponse);

                            // This processes the response, narrowing down to just the keycode. This works as it's supposed to.
                            processResponse(fullResponse);

                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.v(TAG, "...Problem reading input stream");

                    } finally {

                        // Close input stream when I'm done with it.
                        if (inputStream != null) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }).start();

我希望這有幫助...

我想出了解決問題的辦法。 問題正文中的代碼可以保持不變,但是當我創建改造生成器時,我需要添加一個具有read timeoutmax value write timeout的OkHttpClient。

這將導致程序不會因SocketNotFound異常而SocketNotFound ,並且很高興會長時間接受輸入。

這是我的代碼:

    // TODO 9 : Set a timeout for the connection // <- I NEEDED TO ADD THIS BLOCK ***
    OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
            .readTimeout(Integer.MAX_VALUE, TimeUnit.MILLISECONDS)
            .writeTimeout(Integer.MAX_VALUE, TimeUnit.MILLISECONDS)
            .build();

    // TODO 7 : Create retrofit builder
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ClockAPI.ENDPOINT) // Refers to endpoint defined in GithubAPI
            .addConverterFactory(GsonConverterFactory.create(gson)) // Refers to gson builder, created
            .client(okHttpClient) // <- AND THIS LINE ***
            .build();

    // TODO 8 : Create REST API through retrofit builder
    clockUserAPI = retrofit.create(ClockAPI.class);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM