0

I saw an online example of how to impelement a socket connection between an android app and a java server on a pc. The app runs perfectly on the emulator (running 2.3.3) but it force closes on my android smartphone.

After some research I concluded that the solution is to implement an asynctask method. But i'm having problems knowing hot to implement it. I saw many explanations but they didn't help me with my case. This is the sample code that I'm using, I'm going to use this code as a reference template for any further apps I develop.

I know the question has been asked alot (alot alot!), but till now I haven't managed to make this work. So can anybody help me with the following code:

package com.exercise.AndroidClient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class AndroidClient extends Activity {

EditText textOut;
TextView textIn;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);

     textOut = (EditText)findViewById(R.id.textout);
     Button buttonSend = (Button)findViewById(R.id.send);
     textIn = (TextView)findViewById(R.id.textin);
     buttonSend.setOnClickListener(buttonSendOnClickListener);
 }

 Button.OnClickListener buttonSendOnClickListener
 = new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
 // TODO Auto-generated method stub
 Socket socket = null;
 DataOutputStream dataOutputStream = null;
 DataInputStream dataInputStream = null;

 try {
  socket = new Socket("192.168.1.101", 8888);
  dataOutputStream = new DataOutputStream(socket.getOutputStream());
  dataInputStream = new DataInputStream(socket.getInputStream());
  dataOutputStream.writeUTF(textOut.getText().toString());
  textIn.setText(dataInputStream.readUTF());
 } catch (UnknownHostException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 finally{
  if (socket != null){
   try {
    socket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  if (dataOutputStream != null){
   try {
    dataOutputStream.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  if (dataInputStream != null){
   try {
    dataInputStream.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
 ;
}};
}

LogCat

03-03 21:35:59.643: E/Trace(3472): error opening trace file: No such file or directory (2)
03-03 21:36:01.073: D/gralloc_goldfish(3472): Emulator without GPU emulation detected.
03-03 21:36:12.045: D/AndroidRuntime(3472): Shutting down VM
03-03 21:36:12.045: W/dalvikvm(3472): threadid=1: thread exiting with uncaught exception (group=0x40a13300)
03-03 21:36:12.103: E/AndroidRuntime(3472): FATAL EXCEPTION: main
03-03 21:36:12.103: E/AndroidRuntime(3472): android.os.NetworkOnMainThreadException
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:163)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at libcore.io.IoBridge.recvfrom(IoBridge.java:513)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at libcore.io.Streams.readFully(Streams.java:81)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.io.DataInputStream.readShort(DataInputStream.java:169)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:182)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.io.DataInputStream.readUTF(DataInputStream.java:186)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at com.exercise.AndroidClient.AndroidClient$LongOperation.onPostExecute(AndroidClient.java:80)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at com.exercise.AndroidClient.AndroidClient$LongOperation.onPostExecute(AndroidClient.java:1)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.AsyncTask.finish(AsyncTask.java:631)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.AsyncTask.access$600(AsyncTask.java:177)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.os.Looper.loop(Looper.java:137)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at android.app.ActivityThread.main(ActivityThread.java:4745)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.lang.reflect.Method.invokeNative(Native Method)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at java.lang.reflect.Method.invoke(Method.java:511)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
03-03 21:36:12.103: E/AndroidRuntime(3472):     at dalvik.system.NativeStart.main(Native Method)
03-03 21:36:14.722: I/Process(3472): Sending signal. PID: 3472 SIG: 9
nick28
  • 67
  • 3
  • 15

3 Answers3

1

I'm assuming that the Activity has the right permissions to open a socket.

I would guess that the problem with running the code is that you are making an internet connection on the UI thread. This is heavily discouraged, and sometimes simply results in the application stopping.

You are correct that you need to create an AsyncTask with your code and trigger it. Two places to learn about this are: How to execute web request in its own thread? and Is there an accepted best-practice on making asynchronous HTTP requests in Android?

Community
  • 1
  • 1
Neil Townsend
  • 6,024
  • 5
  • 35
  • 52
  • let me check if i got this right. In doInBackground I do my socket connections such as: socket = new Socket("192.168.1.101", 8888); ... and in onPostExecute I use dataOutputStream = new DataOutputStream(socket.getOutputStream());... ? – nick28 Mar 02 '13 at 21:30
  • 1
    Do all the work in doInBackground. Then use onPostExecute to (a) do any UI (screen) operations, (b) update any data lists you are updating from the queries and (c) send any messages to other activities or services which need to know the information or that the connections are completed. – Neil Townsend Mar 03 '13 at 14:16
  • so i made the socket connection in doInBackground and sending and receiving the String in PostExecute. But now when I press the send button the string is sent but then the app force closes! – nick28 Mar 03 '13 at 19:11
  • i updated the post. And now I placed the whole process in doInBackground, the string from the phone is sent to the server but then the app force closes. – nick28 Mar 03 '13 at 19:44
  • i noticed one of the errors says: Only the original thread that created a view hierarchy can touch it's views. So I commented out textIn.setText(dataInputStream.readUTF()); which is now is doInBackground. And the app works now perfectly! But where should I put the command that I commented out so I can change the textfield. – nick28 Mar 03 '13 at 21:21
  • Glad it's coming together. async classes also provide a way to do UI actions while you are running. In doInBackground call publishProgress(/*an int*/) and @Override onProgressUpdate(Integer... progress) in the class to do UI actions. The integers you pass tell onProgressUpdate what UI action to perform (which obviously you write!) See also http://developer.android.com/reference/android/os/AsyncTask.html :-) – Neil Townsend Mar 03 '13 at 21:38
  • thanks alot for your help, going to tinker with the app till it works :) – nick28 Mar 03 '13 at 22:06
  • Pleasure, would appreciate the upvote and/or accept if you feel appropriate. – Neil Townsend Mar 03 '13 at 22:19
0

As Neil said before: you have to do all with the socket in doInBackgroud. Also receiving the string.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • I tried it and got the same result, the string from the phone is sent to the pc server but then the app force closes before recieving the string from the pc. – nick28 Mar 03 '13 at 19:44
  • What kind of exception is there now? – greenapps Mar 03 '13 at 21:12
  • Do you still have that NetworkOnMainThreadExeption? If so then not all network code is in DoOnBackground. Or you instantiate your asynctask with .get() instead of only .execute(). – greenapps Mar 03 '13 at 21:53
0

@nick28: you have an uncaught exception on line 45, what is your line 45? try the following codes before initialising your controls, hopefully your application will not close :

if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
A--C
  • 36,351
  • 10
  • 106
  • 92
WassiM ZgheiB
  • 119
  • 2
  • 2
  • 8