I have an app that connects to a remote chat server and then the user is able to chat. I have a form where the user enters hostname and port and then another form where the user sees all messages and types new ones.
For the networking, it seems, I have no other choice but to use an AsyncTask. But there is something that I don’t know how to do. I would start the networking in the UI when onCreate() is called which is not a problem. But then when I have to wire the networking and the interface it becomes a mess. I have created two asynchronous tasks – one for sending and one for receiving but yet it doesn’t work for me. Here is the code where I first start the SenderTask which is supposed to start communicating by calling the receiver task and if a button shall be pressed a new message is sent:
public class Second extends Activity {
private SenderTask snd;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
// ...
final Button sendButton = (Button) findViewById(R.id.button2);
snd = new SenderTask();
snd.doInBackground(editTexts);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// when the button is clicked the next screen is loaded
snd.onProgressUpdate(true);
}
});
} // end of onCreate
}
Then here is the SenderTask class:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import android.os.AsyncTask;
import android.widget.EditText;
public class SenderTask extends AsyncTask<EditText, Boolean, Void> {
MulticastSocket so;
InetAddress serverAddress;
int port;
EditText eText1;
EditText eText2;
EditText eText3;
EditText messageBoard;
@Override
protected Void doInBackground(EditText... eTexts) {
eText1 = eTexts[0];
eText2 = eTexts[1];
eText3 = eTexts[2];
messageBoard = eTexts[3];
setUp();
return null;
}
private void setUp() {
// convert the host name to InetAddress
try {
//serverAddress = InetAddress.getByName(eText1.getText().toString());
serverAddress = InetAddress.getByName("my server name is here");
} catch (Exception e) {}
//convert the port to an int
//port = Integer.parseInt(eText2.getText().toString());
port = 4456;
// create socket and start communicating
try {
so = new MulticastSocket(port);
so.joinGroup(serverAddress);
} catch (IOException e) {}
// Start listening should be here
ReceiverTask rec = new ReceiverTask();
rec.doInBackground(messageBoard);
rec.onProgressUpdate(so);
}
private void sendMessage() {
// get the text that they contain and add the new messages to the old ones
String message = eText3.getText().toString();
String conversation = messageBoard.getText().toString();
String newConverstion = conversation.concat("\n[You] ").concat(message);
// make the messages text view editable
messageBoard.setFocusable(true);
messageBoard.setText(newConverstion); // add the new message to the text view
messageBoard.setFocusable(false); // make the messages text view not editable
// erase the text on the second text view that has just been sent
eText3.setText("");
// Send message to server
// convert message to bytes array
byte[] data = (message).getBytes();
// create and send a datagram
DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, port);
try {
so.send(packet);
} catch (IOException e) {}
} // end of sendMessage
protected void onProgressUpdate(boolean... go) {
if (go.equals(new Boolean(true))) {
sendMessage();
}
}
}
here is the ReceiverTask class:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import android.os.AsyncTask;
import android.widget.EditText;
public class ReceiverTask extends AsyncTask<EditText, MulticastSocket, Void> {
MulticastSocket so;
EditText messageBoard;
@Override
protected Void doInBackground(EditText... messBo) {
messageBoard = messBo[0];
return null;
}
@Override
protected void onProgressUpdate(MulticastSocket... socket) {
so = socket[0];
byte[] data = new byte[1024]; // received data container
while (true) {
try {
// create a datagram for receivin
DatagramPacket packet = new DatagramPacket(data, data.length);
// wait for the next message
so.receive(packet);
String message = new String(data, 0, packet.getLength());
// add the new messages to the old ones
String conversation = messageBoard.getText().toString();
String newConverstion = conversation.concat("\n[Remote] ").concat(message);
// make the messages text view editable
messageBoard.setFocusable(true);
messageBoard.setText(newConverstion); // add the new message to the text view
messageBoard.setFocusable(false); // make the messages text view not editable
} catch (IOException ioe) {}
}
}
}
The error is:
01-25 14:26:09.739: E/AndroidRuntime(661): FATAL EXCEPTION: main
01-25 14:26:09.739: E/AndroidRuntime(661): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.regeduseroox.projx/com.regeduseroox.projx.Second}: java.lang.NullPointerException
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread.access$600(ActivityThread.java:123)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.os.Handler.dispatchMessage(Handler.java:99)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.os.Looper.loop(Looper.java:137)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread.main(ActivityThread.java:4424)
01-25 14:26:09.739: E/AndroidRuntime(661): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 14:26:09.739: E/AndroidRuntime(661): at java.lang.reflect.Method.invoke(Method.java:511)
01-25 14:26:09.739: E/AndroidRuntime(661): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-25 14:26:09.739: E/AndroidRuntime(661): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-25 14:26:09.739: E/AndroidRuntime(661): at dalvik.system.NativeStart.main(Native Method)
01-25 14:26:09.739: E/AndroidRuntime(661): Caused by: java.lang.NullPointerException
01-25 14:26:09.739: E/AndroidRuntime(661): at com.regeduseroox.projx.ReceiverTask.onProgressUpdate(ReceiverTask.java:33)
01-25 14:26:09.739: E/AndroidRuntime(661): at com.regeduseroox.projx.SenderTask.setUp(SenderTask.java:53)
01-25 14:26:09.739: E/AndroidRuntime(661): at com.regeduseroox.projx.SenderTask.doInBackground(SenderTask.java:27)
01-25 14:26:09.739: E/AndroidRuntime(661): at com.regeduseroox.projx.Second.onCreate(Second.java:38)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.Activity.performCreate(Activity.java:4465)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
01-25 14:26:09.739: E/AndroidRuntime(661): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
01-25 14:26:09.739: E/AndroidRuntime(661): ... 11 more
ReceiverTask.java:33 is so.receive(packet);
SenderTask.java:53 is rec.onProgressUpdate(so);
SenderTask.java:27 is setUp();
Second.java:38 is snd.doInBackground(editTexts);
I don’t know what is wrong now and I really don’t have anymore ideas how to solve this. Any help will be much appreciated.
Replace
with
EDIT
You should not be directly calling
onProgressUpdate()ordoInBackground()to initiate an AsyncTask, onlyexecute(). Furthermore,onProgressUpdate()does its work on the UI thread, which is really only intended to be used to update aProgressBar. You should move all of the work fromonProgressUpdate()todoInBackground(), and return the data inonPostExecute().My suggestion is to create a custom class that includes the
String(conversation) andMulticastSocket(so) as its fields. Send this object in yourAsyncTask.execute()call, and retrieve from the varargs.Eg:
Then in your SenderTask:
You should use this same idea for your Second/SenderTask (take the work out of
onProgressUpdate()).Let me know if this is all clear, and be sure to re-read the docs on the proper usage of AsyncTask.