EDIT: While marked as a duplicate my situation is not the same as the other. I have discovered that serialized objects require the same package name on both the input and output streams. Mismatching package names was my problem.
I have a Java server and client. They are able to connect through sockets and use ObjectInputStream and ObjectOutputStream to send the object Packet back and forth. I have attempted to implement the client in Android. The Android client connects but I am unable to use the streams.
With my current implementation my Android client must be on the same network as my PC with the server running. My PC also has a static IP of 192.168.1.3. The error I get is
java.io.StreamCorruptedException: invalid type code: AC.
I'd post the code for my desktop server and client but I run out of characters. I got the code from here. I've modified that code so when the client connects no string is required. A user sends a ChatMessage (or Packet as I've renamed it) and the message contents are stored with the ClientThread. The client is able to request the last message they sent and the server returns it.
How do I correctly use the object streams with the Android client?
MainActivity:
package com.example.androidclient;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnGetLastMessage, btnSend, btnLogout;
TextView textStatus;
EditText textMessage;
NetworkTask networktask;
private Socket nsocket; // Network Socket
private ObjectInputStream nis; // Network Input Stream
private ObjectOutputStream nos; // Network Output Stream
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnGetLastMessage = (Button) findViewById(R.id.btnGetLastMessage);
btnSend = (Button) findViewById(R.id.btnSend);
btnLogout = (Button) findViewById(R.id.btnLogout);
textStatus = (TextView) findViewById(R.id.textStatus);
textMessage = (EditText) findViewById(R.id.textMessage);
btnGetLastMessage.setOnClickListener(btnGetLastMessageListener);
btnSend.setOnClickListener(btnSendListener);
btnLogout.setOnClickListener(btnLogoutListener);
networktask = new NetworkTask();
networktask.execute();
}
private OnClickListener btnLogoutListener = new OnClickListener() {
public void onClick(View v) {
networktask.SendDataToNetwork(new Packet(
Packet.GET_LAST_MESSAGE));
}
};
private OnClickListener btnGetLastMessageListener = new OnClickListener() {
public void onClick(View v) {
Packet msg = new Packet(Packet.GET_LAST_MESSAGE);
networktask.SendDataToNetwork(msg);
}
};
private OnClickListener btnSendListener = new OnClickListener() {
public void onClick(View v) {
textStatus.setText("Sending Message to AsyncTask.");
Packet msg = new Packet(Packet.SEND_MESSAGE,
textMessage.getText().toString());
networktask.SendDataToNetwork(msg);
}
};
public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {
@Override
protected void onPreExecute() {
Log.i("AsyncTask", "onPreExecute");
}
@Override
protected Boolean doInBackground(Void... params) { // This runs on a
// different thread
boolean result = false;
try {
Log.i("AsyncTask", "doInBackground: Creating socket");
SocketAddress sockaddr = new InetSocketAddress("192.168.1.3",
15000);
nsocket = new Socket();
nsocket.connect(sockaddr); // 10 second connection timeout
if (nsocket.isConnected()) {
// Creating both Data Stream
try {
nis = new ObjectInputStream(nsocket.getInputStream());
nos = new ObjectOutputStream(nsocket.getOutputStream());
} catch (IOException eIO) {
Log.i("AsyncTask",
"doInBackground: Exception creating new Input/output Streams: "
+ eIO);
eIO.printStackTrace();
return false;
}
// creates the Thread to listen from the server
Log.i("AsyncTask",
"doInBackground: Socket created, streams assigned, listening from server");
while (true) {
Log.i("AsyncTask",
"doInBackground: Waiting for data from the server...");
try {
Packet messageFromServer = (Packet) nis
.readObject();
Log.i("ListenFromServer", "messageFromServer: "
+ messageFromServer.getMessage());
textStatus.setText("Last message: "
+ messageFromServer.getMessage());
} catch (IOException e) {
Log.i("ListenFromServer",
"Server has close the connection: " + e);
e.printStackTrace();
break;
} catch (ClassNotFoundException e2) {
// Do nothing
} catch (Exception e) {
Log.i("ListenFromServer", "Generic exception: " + e);
e.printStackTrace();
break;
}
}
}
} catch (IOException e) {
Log.i("AsyncTask", "doInBackground: IOException");
e.printStackTrace();
result = true;
} catch (Exception e) {
Log.i("AsyncTask", "doInBackground: Exception");
e.printStackTrace();
result = true;
} finally {
try {
nis.close();
nos.close();
nsocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.i("AsyncTask", "doInBackground: Finished");
}
return result;
}
public void disconnect() {
try {
nis.close();
nos.close();
nsocket.close();
} catch (Exception e) {
Log.i("AsyncTask", "disconnect: Exception: " + e);
e.printStackTrace();
}
}
public void SendDataToNetwork(Packet msg) { // You run this from
// the
// main thread.
try {
if (nsocket.isConnected()) {
Log.i("AsyncTask",
"SendDataToNetwork: Writing received message to socket");
try {
nos.writeObject(msg);
nos.flush();
} catch (IOException eIO) {
Log.i("AsyncTask",
"doInBackground: Exception during login: "
+ eIO);
eIO.printStackTrace();
nis.close();
nos.close();
nsocket.close();
}
} else {
Log.i("AsyncTask",
"SendDataToNetwork: Cannot send message. Socket is closed");
}
} catch (Exception e) {
Log.i("AsyncTask",
"SendDataToNetwork: Message send failed. Caught an exception");
e.printStackTrace();
}
}
@Override
protected void onProgressUpdate(byte[]... values) {
if (values.length > 0) {
Log.i("AsyncTask", "onProgressUpdate: " + values[0].length
+ " bytes received.");
textStatus.setText(new String(values[0]));
}
}
@Override
protected void onCancelled() {
Log.i("AsyncTask", "Cancelled.");
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
Log.i("AsyncTask", "onPostExecute: Completed with an Error.");
textStatus.setText("There was a connection error.");
} else {
Log.i("AsyncTask", "onPostExecute: Completed.");
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
networktask.cancel(true); // In case the task is currently running
}
}
activity_layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/textMessage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="24sp" />
<Button
android:id="@+id/btnSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Message" >
</Button>
<Button
android:id="@+id/btnGetLastMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get Last Message" >
</Button>
<Button
android:id="@+id/btnLogout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout" >
</Button>
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Status Goes Here"
android:textSize="24sp" />
</LinearLayout>
android manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidclient"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<application
android:allowBackup="true"
android:debuggable="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidclient.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>