for simplicity purpose of demonstrating on how socket programming works in the Android platform, I want to develop a simple socket program without thread/asyntask and also (if possible) without exception caught. Is that possible? I've tried but it doesn't works (as pointed by many others that socket is better to be run at other thread).
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.TextView01);
tv.setText("Nothing from client yet");
}
public Void handleOnClick(View v) {
Socket s = null;
try {
ss = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
try {
s = ss.accept();
BufferedReader input = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String st = null;
st = input.readLine();
mClientMsg = st;
} catch (IOException e) {
e.printStackTrace();
}
}
You can develop anything without using AsyncTask, but I definitely don't recommend it as your application would block until the tasks completes (as I'm sure you already know)! In this case, your socket would need to response fast enough so that the OS doesn't kill your process (see discussions on ANR here).
You will have to handle the Exceptions at one point or another. The best you can do is have your methods throw the exceptions and handle them wherever the method gets called, but this doesn't mean you won't have to handle them; this will just delay them.
public Void handleOnClick(View v) throws IOException {
Socket s = null;
ss = new ServerSocket(SERVERPORT);
s = ss.accept();
BufferedReader input = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String st = null;
st = input.readLine();
mClientMsg = st;
}
If this is meant to be an example or demonstration for others, it should be well structured so that people learn to do things correctly. I would strongly encourage you to consider handling the exceptions where they should be handled (or throw more meaningful exceptions up the chain). Further, if you're teaching a class or an individual these things, you should demonstrate, at one point or another, how to avoid getting slapped with an ANR.
Related
I am having a bit of an issue with my app. I receive a data through a socket, via a BufferedReader. I loop round with while ((sLine = reader.readLine ()) != null) and append the sLine to a StringBuilder object. I also spend a new line \n to the builder.
The plan is that once the builder is all finished, String sTotal = builder.toString()is called and a total is passed to the next routine.
However, the next routine is instead being called once for each line rather than with the string as a whole. The routine call is outside the loop above so I really don't know why!
Hope someone can help...
Edit: Code extract below.
public void run() {
try {
oServerSocket = new ServerSocket(iPort);
while ((!Thread.currentThread().isInterrupted()) && (!bStopThread)) {
try {
oSocket = oServerSocket.accept();
this.brInput = new BufferedReader(new InputStreamReader(this.oSocket.getInputStream()));
StringBuilder sbReadTotal = new StringBuilder();
String sReadXML = "";
while ((sReadXML = brInput.readLine()) != null) {
sbReadTotal.append("\n");
sbReadTotal.append(sReadXML);
}
sReadXML = sbReadTotal.toString();
Log.d("XMLDATA", sReadXML);
processXML(sReadXML);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
/* Nothing Yet */
e.printStackTrace();
}
}
If you're exiting your internal while loop, it means you reached the end of your input stream (that's when readLine() returns null according to the docs).
You should be looking into the client, and not the server. What's establishing the client socket? Are you sure it's not establishing a separate connection for each line it sends?
I have some weird problem on Android 2.2 phone.
I open the socket connection:
socket = new Socket(serverAddr, SERVERPORT);
messageWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), Charset.forName("UTF-8"))));
messageReader = new InputStreamReader(socket.getInputStream(), Charset.forName("UTF-8"));
Start reading in AsyncTask doInBackground():
protected Boolean doInBackground(final Void... unused) {
...
char[] chars = new char[256];
int len;
while((len = messageReader.read(chars))>=0) {
builder.append(chars, 0, len);
break;
}
result = true;
...
}
After reading I close the connection:
try {
socket.close();
socket = null;
} catch (Exception e) {Log.e("socket", "ex");}
try {
messageWriter.close();
messageWriter = null;
} catch (Exception e) {Log.e("writer", "ex");}
try {
messageReader.close();
messageReader = null;
} catch (Exception e) {Log.e("reader", "ex");}
Everything is working fine on Android 2.3 phone and Android 4.0 emulator, but for some reason it's not working on Android 2.2 phone.
The socket is closed, the writer is closed, but the reader is stuck in a while loop even though it should brake loop when calling "socket.close();"... so my closing code is stuck on "messageReader.close();" and whole UI is blocked! ...and there is no way to kill AsyncTask... Why is this happening and what should I do?
First, you don't need those three closes. You only need to close the output stream/writer.
Second, closing isn't guaranteed to terminate a blocking operation in another thread. See the Javadoc. If you have such a thing you need to shutdown the socket for input before closing. Then the reading thread will get an EOS, on which it should exit.
Im having some trouble reading/writing to a tcp server for which im building an app. In a recent thread I was suggested to use a service instead but this is a project for school which suggested asyncTask so I might aswell go for that.
So the classes ive got are my activity class and async, nothing interesting is going on in activity but sending a string which is working so ill get on with the async one.
class ServerTask extends AsyncTask<Void, Void, Void>{
public static String ip = "10.0.2.2";
public static int port = 2002;
Socket socket;
public DataInputStream dis;
public DataOutputStream dos;
public String message;
#Override
protected Void doInBackground(Void... params) {
try {
socket = new Socket(ip, port);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (Exception e) {
Log.i("AsyncTank", "Cannot create Socket");
}
while(socket.isConnected()){
read();
}
}
}
return null;
}
public void write(String message) {
try {
if (socket.isConnected()){
dos.writeUTF(message);
dos.flush();
} else {
Log.i("AsynkTask", "Socket appears to be closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "Writing failed");
}
}
public String read() {
try {
if (socket.isConnected()) {
message = dis.readLine();
} else {
Log.i("AsyncTask", "Cannot read");
}
} catch (Exception e) {
Log.i("AsyncTask", "Cannot read from stream");
}
return message;
}
}
Things I do know, the server DOES get the messages but it doesnt update until I restart the server which leads me to believe that im not pushing a new line or something which makes it all appear as one line after its closed. This however might aswell be the server for which im not reponsible so ill have to read up in that.
The read part however does not want to work, im not sure on how to call the method to have it constantly listen and react to the servers sockt? I tried make a thread just before the return in doInBackGround but then the application starts works for a couple of seconds the force closes due to lack of memory? Do I need a thread to keep constantly listen?
The whole point of this as you might guess is to make a chat so the read method is eventually supposed to update a textView in my activity class. The send method is "working" but not as it should though this might be as I said earlier the server doing some funky buisness.
Another one, is it even possible to have the read as a method like I have or does something have to react when the server sends data and then call the method?
Edit
I have now moved the read part, or atleast some of it to doInBackGround so its now
dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));
message = dis.readLine();
Log.i("AsynkTask", "Read : "+message+" this is doInBackGround!");
This along with a change to simply hardcode a printline in the server made me read that line in the client so im guessing its working realtively good for now.
How is it looking? Is it utter crap this code and should be done some other way? Got my functionality but never bad to learn to do it better so to speak :).
You should do both your writing and reading to the Socket in an AsyncTask's doInBackground() method, as both take time and could block the main (UI) thread. I don't know how you are calling your write() method above but you might also want to take a look at this question that might be related.
I have an application in which there is Google map, location overlays on Google map and a separate thread which send the current location of device to server after every 30 seconds. The problem is that when the thread sends the location to server the screen of device halted until the server respond. Here is the following code,
Global Object
private Handler handlerTimer = new Handler();
In onCreate Method
handlerTimer.removeCallbacks(taskUpdateStuffOnDialog );
handlerTimer.postDelayed(taskUpdateStuffOnDialog , 100);
And here is the taskUpdateStuffOnDialog
private Runnable taskUpdateStuffOnDialog = new Runnable()
{
public void run()
{
try
{
URL url3 = new URL("http://"+ appState.getURL()+"//iLocator/IDForClient.php?reg_no="+ Device_ID[0]);
HttpURLConnection conn = (HttpURLConnection) url3.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String quote = reader.readLine();
while (quote != null)
{
Device_ID = quote.split("\n");
quote = reader.readLine();
bCheckID = true;
}//End While
positionOverlay.setID(Device_ID[0]);
addEvent(Device_ID[0]);
}//End try
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(MainMapActivity.this, "Communication Issue",Toast.LENGTH_LONG).show();
}//End catch
handlerTimer.postDelayed(this, 9000);
}
};
Please tell me what is wrong with my code.
The problem is that, although you're spawning a new Thread, you aren't spawning a new process. Everything you're doing is still in the user interface process, and that's blocking. You can find more information on the topic on developer.android.com.
The quickest and easiest way to get around this is using the IntentService class. It will only allow one HTTP request to be executed at a time, but will take care of all the problems for you.
Try using the AsyncTask for connecting to the Server. See an example here: http://developer.android.com/reference/android/os/AsyncTask.html
I am trying to transfer images quickly between my Android phone and my PC over wifi. I have written code to do this but it can 4-5 seconds to transfer one 640x480px image across. I am wondering is my method flawed and is there a faster way to do this?
Here is the Server code
void main(String[] args)
{
try {
ServerSocket serverSocket = new ServerSocket(5555);
Socket clientSocket = serverSocket.accept();
long startTime = System.currentTimeMillis();
InputStream clientInputStream = clientSocket.getInputStream();
BufferedImage BI = ImageIO.read(clientInputStream);
long endTime = System.currentTimeMillis();
ImageIO.write(BI,"png",new File("test.png"));
System.out.println((endTime - startTime) + " ms.");
} catch (IOException e)
{
e.printStackTrace();
}
}
}
Here is the Android client code
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bitmap imageToSend = BitmapFactory.decodeResource(this.getResources(),R.drawable.img);
try
{
Socket socket = new Socket("192.168.1.1",5555);
imageToSend.compress(CompressFormat.PNG,0 , socket.getOutputStream());
}
catch (Exception e) {
e.printStackTrace();
}
}
Thank you for any help you can give.
Two things I can think of:
Use a buffered output stream in your output e.g.
new BufferedOutputStream(socket.getOutputStream());
Write the image to disk first. Then try to open sockets in parallel each transferring a different offset of the image (e.g. split the image to 3 jobs, transfer each in parallel to the others). This will workaround some TCP behaviors.