2

I am trying to make a simple app. Where user sees one edittext .. enters some text in it.. and then press send... then the server on laptop receives that message.

Now the NetworkOnMainThread exception is giving me Headaches......the app works perfectly for 2.3.3 because there was no such thing as NetworkOnMainThread Exception that time.

Having searched a lot .. Two solutions are

  1. Making new thread for networking OR
  2. AsyncTask.

I tried both without any results.

Try 1: With Separate Thread:

Now what I could understand is that I had to start a separate thread. Ok. I did.

Following is my client side code.

EditText e ;
TextView tv;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    e= (EditText) findViewById(R.id.editText1);
    tv = (TextView) findViewById(R.id.textView1);
    Thread startNetworking = new Thread(new NetworkThread());
    startNetworking.start();
}

public void sendMessage(View v){
        if(NetworkThread.sendToClient(e.getText().toString()))
            tv.setText("Status : Successful");
        else
            tv.setText("Status : Unsuccessful");
}

sendMessage is onClick function for my send button. I have another JAVA file NetworkThread.java....

Here is a code for that :

public class NetworkThread implements Runnable{

static DatagramSocket socket;
static InetAddress add;
public void run() {
    try {
        socket = new DatagramSocket();
    } catch (SocketException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        add = InetAddress.getByName("192.168.1.12");
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
public static boolean sendToClient(String message){
    DatagramPacket p = new DatagramPacket(message.getBytes(),message.getBytes().length,add,4444);
    try {
        socket.send(p);
        return true;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return false;
    }
}
}

This is still doesn't work. I first want to exhaust this first try then I will move onto asking here about AsyncTask and what I have tried. So for time being please help me achieve this simple task of sending and receiving a string.

Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
PrateekArora
  • 131
  • 7
  • 1
    have you searched google on this topic? there are a lot similar questions in here: https://www.google.com/search?q=NetworkOnMainThread+asynctask example: https://gist.github.com/3117827 – Bruno Bieri Oct 13 '12 at 14:12
  • yes i have. But my problem with AsyncTask , i have commented on below answer. If that is solved , then i am happy to use AsyncTask. – PrateekArora Oct 13 '12 at 14:24

1 Answers1

2

Unfortunately, having sendToClient() defined in the same class as NetworkThread doesn't mean that it will run on your network-specific thread. The sendToClient() method will still run on your main (UI) thread because it's being called from your onClick() method. UI callbacks, such as onClick(), are always processed on the UI thread.

I would recommend using an AsyncTask as it enables you to send arbitrary data (such as your message parameter) to the background/network thread before it executes. Continuing to use Runnable and Thread will require extra machinery to synchronize the execution of your UI and network threads, and these challenges are handled behind the scenes by AsyncTask.

acj
  • 4,821
  • 4
  • 34
  • 49
  • 2
    you can find a AsyncTask example here: http://stackoverflow.com/questions/9671546/asynctask-android-example – Bruno Bieri Oct 13 '12 at 14:15
  • ok, if i use AsyncTask , what i dont understand is that i give a statement like this in onClick right "myAsync.execute(new String[]{msg})"? Now everytime i click button , AsyncTask creates new thread ? and if it does , what about previous threads ? does it close them automatically. Also where would i initialize my sockets ? – PrateekArora Oct 13 '12 at 14:19
  • 1
    If it makes sense for your application, you may launch the `AsyncTask` from your `onClick` method. Prior to Android 3.0, `AsyncTask` will make a new thread each time. In 3.0+, it will reuse a small number of threads and will process each of them in sequence. Socket initialization should be done outside of the `AsyncTask` if you want to reuse the socket. (Alternatively, you could use a [singleton pattern](http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html) inside of the `AsyncTask`. The right answer depends on your app requirements and personal preference.) – acj Oct 13 '12 at 14:25
  • Ok , my main concern regarding starting of new thread each time was because of setting of socket again and again. If i want to reuse sockets , where should i initialize them ? if i do them in main thread , won't that count as NetworkOnMainThread ? Also , while i am on this topic , Does just initialising socket count as NetworkOnMainThread or when i send packet , only that counts ?? – PrateekArora Oct 13 '12 at 14:28
  • 1
    Calling `new DatagramSocket()` shouldn't throw a `NetworkOnMainThreadException`, but doing `add = InetAddress.getByName(...)` will because it uses the network. The most straightforward solution for reusing the socket is probably to use a singleton. Please check out the link I included in my last comment. – acj Oct 13 '12 at 14:32
  • Great !! got it working.. Thanks alot. One more ques.. calling .execute method again and again won't cause any problems right ? Because the main application i am aiming for requires to send coordinates where user touches ... so probably i need to call .execute everytime using onTouchListener. Is it advisable to do so ? – PrateekArora Oct 13 '12 at 15:08
  • 1
    I don't think you'll experience any problems doing so. Sending a datagram is a fast operation, so the requests shouldn't queue up too much. If you're concerned about it, you can use the DDMS tool in Android's ADT plugin to view the current set of threads for your process. – acj Oct 13 '12 at 15:28