I'm trying to create an android Telnet client. I'm using the TelnetClient class and create an object. Then i get an InputStream with getInputStream() and from it i create an InputStreamReader. This runs on a separate from the main thread. The TelnetInputAvailable() of a TelnetInputListener object is called every time the input buffer goes from zero to none zero bytes. So inside this method i try to get the data calling the read() method of the InputStreamReader object.
The problem is that the InputStreamReader's read() method returns ALWAYS ONLY one character. Then the TelnetInputAvailable() method has to be called for a new character to be fetched.
The same happens also if i just use an InputStream and get bytes. Only one byte i get every time.
Do you know how can i get more than one character?
If you use the read() method, you are explicitly asking for a single byte or character. To read more than one, use the read method that takes an array. There are actually two overloaded versions, but I hardly ever use the indexed one.
Regardless of the one you're using, the read will fill elements from the offset (0 for the non-indexed overloaded version), and return the number of elements filled. This can be 0, but the only return value that indicates nothing was left is -1.
A small example of how to read everything from a Reader (for InputStream, replace char with byte, the process is the same):
Hello Rob Spoor.
I had already used the method you describe in your post. Also in this case only one character is read
in the buffer. Using your EXACT code snippet after reading the first character the while loop is stuck
in the condition evaluation for ever. Only if i use reader.reset() in the while body it continues reading
all the characters (although it raises errors for not supported method).
What i understand is that the TelnetClient class somehow prevents the InputStream it uses from reading more
than one byte/character even if i give it a buffer as argument. This makes the TelnetInputListener class
useless as its telnetInputAvailable() method runs only once for the whole program flow.
For now i use the following code to do my job:
I've dived into the code a bit, and it seems that the listener can indeed be triggered for each single byte. The listener is notified by calling (package private) method TelnetClient.notifyInputListener(). This is done by (package private) class TelnetInputStream in a background thread. This calls a private method, __processChar. If this method returns true, the client notifyInputListener() method is called. And this method returns only true if the object's internal buffer was empty before. There is some buffering possible (because TelnetInputStream extends BufferedInputStream) but I think that can only be used if you don't use the listener.
Now your code looks pretty good, but I would suggest some small changes, mostly for performance reasons. You're now:
1) Creating a new InputStreamReader every time. This may even lead to bugs in case the InputStreamReader consumes several bytes without reporting them immediately.
2) Converting the char you read into a String.
3) Using String concatenation for probably quite a lot of chars. That means that your message += s is actually quite a few occurrences of message = new StringBuilder().append(message).append(s).toString() 4) If there's an IOException while reading you will append the String "null" (because that's what will happen if append null to a String).
5) You're using new String(message) where message already is a String. That creates a new String unnecessarily.
6) You're using == true, something that's never necessary.
The following is a quick attempt to fix the above (with not-so-great error handling though):
There is one thing I would suggest you try in the above - instead of doing a single read, do a read while sreader.ready(). That way you will still read all chars if the listener is triggered for more than one char.
Thank you Rob spoor! So it seems i have to tackle the TelnetClient code to make the TelnetInputStream public or something like this. But i'll just make the corrections that you suggested in the code and not mess with the libraries internals. Thank you very much for the corrections too!