changing the value of variable in thread while its running - java

I am building an android app in which service is running and it has a thread which listens for tcp connections and receive the message and respond back.Actually what I want to do is to give the user the choice to respond with yes or no ,when the thread will accept the connection, My service class is this:
public class Receiver extends Service {
static String TCP_RECEIVE = "soft.b.peopleassist";
public static String ip;
DatagramSocket socket;
private WifiManager.WifiLock wifiLock=null;
private PowerManager.WakeLock wakeLock=null;
volatile public static String outgoingMsg="null";
#SuppressLint("DefaultLocale")
public String getIpAddr() {
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
String ipString = String.format(
"%d.%d.%d.%d",
(ip & 0xff),
(ip >> 8 & 0xff),
(ip >> 16 & 0xff),
(ip >> 24 & 0xff));
return ipString;
}
private void listenAndWaitAndThrowIntent(Integer port) throws Exception {
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
//ss.setSoTimeout(10000);
//accept connections
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//receive a message
String incomingMsg = in.readLine() + System.getProperty("line.separator");
JSONObject jsonObj = new JSONObject();
try {
jsonObj = new JSONObject(incomingMsg);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
String trans=(String) jsonObj.get("TranId");
String ide=(String) jsonObj.get("Amount");
String hashs=(String) jsonObj.get("Basket");
incomingMsg=trans+","+ide+","+hashs;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("TcpServer", "received: " + incomingMsg);
//send a message
// String outgoingMsg = "goodbye from port " + port + System.getProperty("line.separator");
// outgoingMsg = "ok";
broadcastIntent(incomingMsg);
incomingMsg=null;
Thread.sleep(3000);
out.write(outgoingMsg);
out.flush();
Log.i("TcpServer", "sent: " + outgoingMsg);
broadcastIntent(incomingMsg);
//SystemClock.sleep(5000);
s.close();
outgoingMsg="null";
} catch (InterruptedIOException e) {
//if timeout occurs
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void broadcastIntent(String message) {
Intent intent = new Intent(Receiver.TCP_RECEIVE);
intent.putExtra("messages", message);
sendBroadcast(intent);
}
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
// InetAddress broadcastIP = InetAddress.getByName(ip); //172.16.238.42 //192.168.1.255
Integer port = 21111;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(port);
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
private Boolean shouldRestartSocketListen=true;
void stopListen() {
shouldRestartSocketListen = false;
if(socket!=null)
socket.close();
}
#Override
public void onCreate() {
Log.i("Service", "WiFi lOCK");
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
wifiLock.acquire();
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Lock");
wakeLock.acquire();
};
#Override
public void onDestroy() {
stopListen();
wifiLock.release();
wakeLock.release();
Log.i("UDP", "Service stoped");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
shouldRestartSocketListen = true;
startListenForUDPBroadcast();
Log.i("TCP", "Service started");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
outGoingMsg is the message which is actually a response.Now I want the thread to wait until the value of this variable in thread is not changed.There is another class from where I want to change this variable.For now am calling sleep to sleep this thread for few seconds but its not the right way because if after few seconds user don't respond it will automatically send null..please help how can I do this..

you can put the waiting action into an loop, which breaks if the value is set.
for reasons of visibility you should use an volatile modifier.
I'll post an example in a minute.
volatile String valueIAmWaitingFor; // Class Variable
...
while(valueIAmWaitingFor == null){
Thread.sleep(3000);
}
//go on
The other method can now set valueIAmWaitingFor.
volatile:
Declaring a volatile Java variable means: The value of this variable
will never be cached thread-locally: all reads and writes will go
straight to "main memory"; Access to the variable acts as though it
is enclosed in a synchronized block, synchronized on itself.
This is just one way to do this. There are many more secure solutions (but also more complex than this hotfix)
EDIT: of course it has to be valueIAmWaitingFor == null, and not valueIAmWaitingFor != null

Related

How to separate received digits two by two

I'm working on a project which receives information from an arduino module and shows it as a chart.
The problem is I have 5 elements ( temperature,humidity, etc... ) and the code I have can only receive one number at a time ( for example : 2838752458 ), as you see in the example the number has 10 digits which comes from Arduino and I want to separate them two by two so each two of them goes for one element.
you might ask why I don't set a handler so I can receive each two number at a separated time but I've tried that and it gives me closed application error because the code I have only can receive one number at a time.
public class Analysies extends AppCompatActivity {
Handler h;
String tekrar = "";
String dama = "";
String qaza = "";
String faaliat = "";
String rotobat = "";
private OutputStream outStream = null;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static String address = "00:21:13:00:02:5B";
final int RECIEVE_MESSAGE = 1; // Status for Handler
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder sb = new StringBuilder();
private Analysies.ConnectedThread mConnectedThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_analysies);
gifImageView = (GifImageView) findViewById(R.id.gifBro);
txt1 = (GifImageView) findViewById(R.id.afterAutotxt);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
txt1.animate().alpha(1f).setDuration(2000);
}
}, 1000);
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
// if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new
String(readBuf, 0, msg.arg1);
// create string from bytes array
sb.append(strIncom);
// append string
int endOfLineIndex = sb.indexOf("\r\n");
// determine the end-of-line
if (endOfLineIndex > 0) {
// if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length());
sbprint.getBytes().toString();
////////////////////////////// HERE IS WHERE I CAN RECEIVE INFORMATION FROM ARDUINO ///////////////////////////////
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
// Toast.makeText(CommunicationAuto.this, "String:" + sb.toString() , Toast.LENGTH_LONG).show();
break;
}
}
;
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
if(Build.VERSION.SDK_INT >= 10){
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
return (BluetoothSocket) m.invoke(device, MY_UUID);
} catch (Exception e) {
// Toast.makeText(getApplicationContext(), "Could not Insecure", Toast.LENGTH_SHORT).show();
}
}
return device.createRfcommSocketToServiceRecord(MY_UUID);
}
#Override
public void onResume() {
super.onResume();
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
// Toast.makeText(getApplicationContext(), "Socket failed", Toast.LENGTH_SHORT).show();
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
btAdapter.cancelDiscovery();
// Establish the connection. This will block until it connects.
// Toast.makeText(getApplicationContext(), "Connecting", Toast.LENGTH_SHORT).show();
try {
btSocket.connect();
// Toast.makeText(getApplicationContext(), "Connecting ok!", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
// errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
mConnectedThread = new Analysies.ConnectedThread(btSocket);
mConnectedThread.start();
}
#Override
public void onPause() {
super.onPause();
try {
btSocket.close();
} catch (IOException e2) {
// errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
}
}
private void checkBTState() {
// Check for Bluetooth support and then check to make sure it is turned on
// Emulator doesn't support Bluetooth and will return null
if(btAdapter==null) {
Toast.makeText(getApplicationContext(), " Bluetooth is not supported. ", Toast.LENGTH_SHORT).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
private void errorExit(String title, String message){
Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
finish();
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}
}
}
The question : How can i separate the 10 digit number two by two and add them to separated integers so i can pass them to the chart activity? Please give me an example for "1234567890" this number.
here is the output of the chart I created so far.
This seems to do what you want:
import java.util.regex.*;
public class HelloWorld{
public static void main(String []args){
String s = "1234567890";
String pattern = "(\\d\\d)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(s);
while (m.find()) {
System.out.println(m.group(0));
}
}
}
And output:
12
34
56
78
90
At first make sure the number of your digits (e.g: 1234567890) always divisible by 2. Well, then I have a little hack for you.
First, convert the digits to String and run a for-loop with step 2, then just append the characters at i-th and (i+1)th position into each string producing using the loop into an array. And finally, you can just read item from the array list and send value to your chart just parsing the String into int value to your chart. Here is a sample code I did with Kotlin (but I can convert it into Java code if you need). If you face any issues, feel free to comment.
fun main() {
val digits = 1234567890
val arr = arrayListOf<String>()
for (i in 0 until digits.toString().length step 2) {
val sub = "${digits.toString()[i]}${digits.toString()[i+1]}"
arr.add(sub)
}
println(arr)
}

java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 3 years ago.
I am want to separate the strings incoming from arduino and store it in variables for database purposes but when I try to divide that string using split() after a few moments the exception occurs
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 and the app keeps stopping
the error is at Line 203 separated[1]
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Android-Arduino";
Button btnOn, btnOff;
TextView temperatureText, heartbeatText;
Handler h;
final int RECIEVE_MESSAGE = 1;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder sb = new StringBuilder();
private ConnectedThread connectedThread;
// Common service that bluetooth device support
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// MAC address of the bluetooth module.
private static String address = "00:18:E4:35:75:A6";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
temperatureText = (TextView) findViewById(R.id.temp);
heartbeatText = (TextView)findViewById(R.id.heartbeat);
getDataArduino();
// Bluetooth adapter
btAdapter = BluetoothAdapter.getDefaultAdapter();
// Check whether the bluetooth is enabled / disabled
checkBTState();
}
// Creates the communication chanel
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
if(Build.VERSION.SDK_INT >= 10){
try {
final Method m = device.getClass().
getMethod("createInsecureRfcommSocketToServiceRecord", new Class[]{UUID.class });
return (BluetoothSocket) m.invoke(device, MY_UUID);
} catch (Exception e) {
Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
}
return device.createRfcommSocketToServiceRecord(MY_UUID);
}
#Override
public void onResume() {
super.onResume();
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: "
+ e.getMessage() + ".");
}
btAdapter.cancelDiscovery();
try {
btSocket.connect();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException ex) {
errorExit("Fatal Error", "In onResume() and unable to close socket during " +
"connection failure" + ex.getMessage() + ".");
}
}
// Creates the data stream with the server
connectedThread = new ConnectedThread(btSocket);
connectedThread.start();
}
#Override
public void onPause() {
super.onPause();
try {
btSocket.close();
} catch (IOException ex) {
errorExit("Fatal Error", "In onPause() and failed to close socket." +
ex.getMessage() + ".");
}
}
private void checkBTState() {
// Checks if the devices has bluetooth functionalities
if(btAdapter==null) {
errorExit("Fatal Error", "Bluetooth not support");
} else {
// Checks if the bluetooth is on
if (btAdapter.isEnabled()) {
} else {
// Prompt user to turn on Bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
private void errorExit(String title, String message){
Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
finish();
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
// Get number of bytes and message in "buffer"
bytes = mmInStream.read(buffer);
// Send to message queue Handler
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
//Call this from the main activity to send data to the remote device
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
Log.d(TAG, "...Error data send: " + e.getMessage() + "...");
}
}
}
public void getDataArduino() {
temperatureText.clearComposingText();
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1);
sb.append(strIncom);
int endOfLineIndex = sb.indexOf("\n");
if (endOfLineIndex > 0) {
String sbprint = sb.substring(0, endOfLineIndex);
sb.delete(0, sb.length());
String[] separated = sbprint.split(":");
heartbeatText.setText(separated[0]+ "");
temperatureText.setText(separated[1]+ "");
}
Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
}
};
}
}
I need the temperature to display differently and heartrate to be displayed individually.
You can first try to print the input data (StringBuffer sb) and split String array(String[] separated). You are getting error because the Strings have not split as your expected and only 1 element is present in the array sbprint, this is why when you try to access the second element you get ArrayIndexOutofBound index.
Once you print the Split String Array it would give you an idea where your data is wrong.

How to transmit of stream of data to multiple devices using sockets in Android?

I am trying to transmit a continuous stream of data to multiple devices over a portable hotspot connection using sockets.
I am facing two problems:
The message only gets displayed to the client AFTER all the messages are displayed in msg TextView on the server end. So if I use an infinite while(true) loop instead of for(int i = 0; i < 1000; i++), in ServerSocketReplyThread, the message never gets transmitted, and the client eventually crashes
I am unable to connect another client to the server until all the messages have been transmitted to the first client.
How do I structure the code to ensure simultaneous, real-time transmission to multiple clients?
Here's what the code looks like:
I am using an activity called Transmit activity, where I am instantiating the msg Textview, which replays the sent messages, and a server object.
msg = (TextView) findViewById(R.id.server_replayed_messages);
Server server = new Server(this);
The Server class is as follows:
public class Server {
TransmitActivity activity;
ServerSocket serverSocket;
String message = "";
static final int socketServerPORT = 8080;
ArrayList<Socket> socketList = new ArrayList<Socket>();
public Server(TransmitActivity a) {
this.activity = a;
Thread socketServerThread = new Thread(new SocketServerThread());
socketServerThread.start();
}
public int getPort() {
return socketServerPORT;
}
public void onDestroy() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
int count = 0;
#Override
public void run() {
try {
// create ServerSocket using specified port
serverSocket = new ServerSocket(socketServerPORT);
while (true) {
// block the call until connection is created and return
// Socket object
Socket socket = serverSocket.accept();
count++;
message += "#" + count + " from "
+ socket.getInetAddress() + ":"
+ socket.getPort() + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread =
new SocketServerReplyThread(socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
for(int i = 0; i < 1000; i++) {
String msgReply = DateFormat.getDateTimeInstance().format(new Date());
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.flush();
message += "replayed: " + msgReply + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong in SocketServerReplyThread! " + e.toString() + "\n";
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
}
}
}
}
On the client side I have a ReceiveActivity, where I am using the following code when a "Connect" button is clicked:
Client myClient = new Client(editTextAddress.getText()
.toString(), Integer.parseInt(editTextPort
.getText().toString()), response);
myClient.execute();
The Client class is as follows:
public class Client extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String response = "";
TextView textResponse;
Client(String addr, int port, TextView textResponse) {
dstAddress = addr;
dstPort = port;
this.textResponse = textResponse;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
/*
* notice: inputStream.read() will block if no data return
*/
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}
Any help would be much appreciated.

Phonegap : BluetoothChatExample [Android]

I try to develop a minimalistic BluetoothChat for Android with Phonegap. The Plugin is based on the Android SDK Example of the BluetoothChat as you can see in the example code.
The native BluetoothChat works fine.
The Problem is, when i call my "write"-Function, the "ConnectedThread" is always null, although the connection is established.
I can't recognize where it is set to null again, after the State was set to 3 (STATE_CONNECTED).
So when i run the program native on android, it works fine and the state during write is always 3, but when i use my phonegap plugin 'r'(ConnectedThread) becomes null :
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
Log.i(TAG, "State "+mState);
if (mState != STATE_CONNECTED) return;
Log.i(TAG, "Connected Thread "+mConnectedThread);
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
I used a lot of debug messages, but i was never informed that the state is null again.
Full source code :
PLUGIN.java
public class BluetoothConnection extends CordovaPlugin {
//Android specific tag-messages
private static final String TAG ="BluetoothConnection";
private static final boolean D = true;
// Member-Variables
public BluetoothAdapter mBluetoothAdapter;
public JSONArray mListOfDiscoveredDevices;
public String mConnectedDeviceName;
public ConnectionHandler mConnectionHandler;
// Phonegap-specific actions, which call the function
public String ACTION_ENABLEBLUETOOTH = "enableBluetooth";
public String ACTION_DISABLEBLUETOOTH = "disableBluetooth";
public String ACTION_DISCOVERDECIVES = "discoverDevices";
public String ACTION_STOPDISCOVERDEVICES = "stopDiscoverDevices";
public String ACTION_CREATEBOND = "createBond";
public String ACTION_WRITEMESSAGE = "writeMessage";
// not usable, this moment
public String ACTION_DISCONNECT = "disconnect";
//Message types sent from the ConnectionHandler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
#Override
public boolean execute(String action, JSONArray args,
CallbackContext callbackContext) throws JSONException {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter.equals(null)) {
Log.i(TAG, "no adapter was found");
}
mConnectionHandler = new ConnectionHandler(mHandler);
if (action.equals(ACTION_ENABLEBLUETOOTH)) {
enableBluetooth();
}
else if (action.equals(ACTION_DISABLEBLUETOOTH)) {
disableBluetooth();
}
else if (action.equals(ACTION_DISCOVERDECIVES)) {
discoverDevices();
}
else if (action.equals(ACTION_STOPDISCOVERDEVICES)) {
stopDiscovering(callbackContext);
}
else if (action.equals(ACTION_CREATEBOND)) {
try {
BluetoothDevice remoteBtDevice = createBond(args, callbackContext);
connect(remoteBtDevice, callbackContext);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(action.equals(ACTION_WRITEMESSAGE)){
writeMessage(args.getString(0));
}
else if (action.equals(ACTION_DISCONNECT)) {
disconnect();
}
return false;
}
public void enableBluetooth() {
if (!mBluetoothAdapter.equals(null)) {
mBluetoothAdapter.enable();
Log.i(TAG, "bluetooth on");
}
}
public void disableBluetooth() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
Log.i(TAG, "bluetooth off");
}
}
public void discoverDevices() {
mListOfDiscoveredDevices = new JSONArray();
Log.i("Log", "in the start searching method");
IntentFilter intentFilter = new IntentFilter(
BluetoothDevice.ACTION_FOUND);
cordova.getActivity().registerReceiver(mFoundDevices, intentFilter);
mBluetoothAdapter.startDiscovery();
}
private void stopDiscovering(CallbackContext callbackContext) {
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
PluginResult res = new PluginResult(PluginResult.Status.OK,
mListOfDiscoveredDevices);
res.setKeepCallback(true);
callbackContext.sendPluginResult(res);
Log.i("Info", "Stopped discovering Devices !");
}
public BluetoothDevice createBond(JSONArray args, CallbackContext callbackContext) throws Exception {
String macAddress = args.getString(0);
Log.i(TAG, "Connect to MacAddress "+macAddress);
BluetoothDevice btDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
Log.i("Device","Device "+btDevice);
Class class1 = Class.forName("android.bluetooth.BluetoothDevice");
Method createBondMethod = class1.getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
if(btDevice.equals(null))
throw new NullPointerException("Remote BluetoothDevice could not be paired !");
return btDevice;
}
public void removeBond(BluetoothDevice btDevice) throws Exception {
Class btClass = Class.forName("android.bluetooth.BluetoothDevice");
Method removeBondMethod = btClass.getMethod("removeBond");
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
}
public void connect(BluetoothDevice btDevice, CallbackContext callbackContext) {
if(!btDevice.equals(null)){
mConnectionHandler.connect(btDevice, false);
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
Log.i(TAG, "Status after connecting "+mConnectionHandler.getState());
}
else {
callbackContext.error("Could not connect to "+btDevice.getAddress());
}
}
public void disconnect(){
}
public void writeMessage(String message){
if(mConnectionHandler.getState() != ConnectionHandler.STATE_CONNECTED){
Log.i(TAG, "Could not write to device");
Log.i(TAG, "State "+mConnectionHandler.getState());
}
if(message.length() > 0) {
byte[] send = message.getBytes();
mConnectionHandler.write(send);
Log.i(TAG, "sending "+message);
}
else {
Log.i(TAG, "There is nothing to send.");
}
}
private BroadcastReceiver mFoundDevices = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Message msg = Message.obtain();
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Toast.makeText(context, "found Device !", Toast.LENGTH_SHORT).show();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i("FOUND", "Name " + device.getName() + "-" + device.getAddress());
JSONObject discoveredDevice = new JSONObject();
try {
discoveredDevice.put("name", device.getName());
discoveredDevice.put("adress", device.getAddress());
if (!isJSONInArray(discoveredDevice)) {
mListOfDiscoveredDevices.put(discoveredDevice);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
};
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case ConnectionHandler.STATE_CONNECTED:
Log.i(TAG, "ConnectionHandler.STATE_CONNECTED !");
break;
case ConnectionHandler.STATE_CONNECTING:
Log.i(TAG, "ConnectionHandler.STATE_CONNECTING !");
break;
case ConnectionHandler.STATE_LISTEN:
Log.i(TAG, "ConnectionHandler.STATE_LISTEN !");
break;
case ConnectionHandler.STATE_NONE:
Log.i(TAG, "ConnectionHandler.STATE_NONE !");
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
Log.i(TAG, "Write "+writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
Log.i(TAG, "Read "+readMessage);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Log.i(TAG, mConnectedDeviceName);
break;
case MESSAGE_TOAST:
String message = msg.getData().getString(TOAST);
Log.i(TAG, "Connection lost : " +message);
break;
}
}
};}
CONNECTION-HANDLER
public class ConnectionHandler {
// Debugging
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// Name for the SDP record when creating server socket
private static final String NAME_SECURE = "BluetoothChatSecure";
private static final String NAME_INSECURE = "BluetoothChatInsecure";
// Unique UUID for this application
private static final UUID MY_UUID_SECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final UUID MY_UUID_INSECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mSecureAcceptThread;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
public ConnectionHandler(Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(BluetoothConnection.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if (D) Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
setState(STATE_LISTEN);
// Start the thread to listen on a BluetoothServerSocket
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
mSecureAcceptThread.start();
}
if (mInsecureAcceptThread == null) {
mInsecureAcceptThread = new AcceptThread(false);
mInsecureAcceptThread.start();
}
}
public synchronized void connect(BluetoothDevice device, boolean secure) {
if (D) Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device, secure);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device, final String socketType) {
if (D) Log.d(TAG, "connected, Socket Type:" + socketType);
// Cancel the thread that completed the connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// Cancel the accept thread because we only want to connect to one device
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BluetoothConnection.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
Log.i(TAG, "State "+mState);
if (mState != STATE_CONNECTED) return;
Log.i(TAG, "Connected Thread "+mConnectedThread);
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
private void connectionFailed() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothConnection.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
ConnectionHandler.this.start();
}
private void connectionLost() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothConnection.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
ConnectionHandler.this.start();
}
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
mSocketType = secure ? "Secure":"Insecure";
// Create a new listening server socket
try {
if (secure) {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
MY_UUID_SECURE);
} else {
tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
NAME_INSECURE, MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "Socket Type: " + mSocketType +
"BEGIN mAcceptThread" + this);
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (ConnectionHandler.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
}
public void cancel() {
if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThread" + mSocketType);
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType +
" socket during connection failure", e2);
}
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (ConnectionHandler.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothConnection.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
ConnectionHandler.this.start();
break;
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothConnection.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}}
Thanks !!!
I implemented again in a new project - now it works, don't know why - but it work now.

Why are my client threads/listeners not receiving broadcasted messages from the server?

I made a simple prototype of a client-server application on Android
I managed to connect two clients to the server and the server can receive their messages. The problem now is that I can't seem to broadcast/receive the messages to other clients.
I try to broadcast the received message through a for loop in the Server class:
private void broadcastMessage(String message) {
for (int i = 0, j = clients.size(); i <= j; i++) {
PrintWriter out = null;
Socket socket = clients.get(i);
try {
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// WHERE YOU ISSUE THE COMMANDS
out.println(message);
Log.d("SERVER Loop", "Broadcasting messages...");
out.close();
}
Log.d("SERVER", "Message Brodcasted");
}
This I then try to receive through a listener in the Client class :
public class ClientThreadListener implements Runnable {
protected Socket serverSocket = null;
protected String mMsgFromServer;
public ClientThreadListener(Socket serverSocket) {
this.serverSocket = serverSocket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
serverSocket.getInputStream()));
while ((mMsgFromServer = in.readLine()) != null) {
Log.d("MESSAGE FROM SERVER: ", mMsgFromServer);
handler.post(new Runnable() {
#Override
public void run() {
msgFromOtherClients.append('\n'
+ "Message From Server: " + mMsgFromServer);
}
});
}
} catch (Exception e) {
Log.e("ClientListener", "C: Error", e);
connected = false;
}
}
}
I don't get any errors or force closes though. Forgive me I know it is very messy but please bear with me and please focus on the issue at hand instead :D
Here is the full code for the Server class
public class Server extends Activity {
private TextView serverStatus;
// DEFAULT IP
public static String SERVERIP = "10.0.2.15";
// DESIGNATE A PORT
public static final int SERVERPORT = 8080;
private Handler handler = new Handler();
private ServerSocket serverSocket;
private String mMsgFromClient;
private MultiThreadedServer server;
private ArrayList<Socket> clients = new ArrayList<Socket>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.server);
serverStatus = (TextView) findViewById(R.id.server_status);
// SERVERIP = getLocalIpAddress();
server = new MultiThreadedServer(8080);
new Thread(server).start();
}
public class MultiThreadedServer implements Runnable {
protected int serverPort = 8080;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
public MultiThreadedServer(int port) {
this.serverPort = port;
}
public void run() {
synchronized (this) {
this.runningThread = Thread.currentThread();
}
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
clients.add(clientSocket);
} catch (IOException e) {
if (isStopped()) {
Log.d("SERVER TEXT", "Server Stopped.");
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
new Thread(new WorkerRunnable(clientSocket, this)).start();
}
Log.d("SERVER TEXT", "Server Stopped.");
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop() {
this.isStopped = true;
try {
this.serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port 8080", e);
}
}
private void broadcastMessage(String message) {
for (int i = 0, j = clients.size(); i <= j; i++) {
PrintWriter out = null;
Socket socket = clients.get(i);
try {
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// WHERE YOU ISSUE THE COMMANDS
out.println(message);
Log.d("SERVER Loop", "Broadcasting messages...");
out.close();
}
Log.d("SERVER", "Message Brodcasted");
}
}
public class WorkerRunnable implements Runnable {
protected Socket clientSocket = null;
protected String mMsgFromClient = null;
private UUID id;
public WorkerRunnable(Socket clientSocket, MultiThreadedServer server) {
this.clientSocket = clientSocket;
id = UUID.randomUUID();
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while ((mMsgFromClient = in.readLine()) != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.append('\n'
+ "Message From Client ID " + getID()
+ ": " + mMsgFromClient);
}
});
}
Log.d("SERVERTEXT", "Proceed to broadcast");
server.broadcastMessage(mMsgFromClient);
} catch (IOException e) {
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
serverStatus
.append('\n'
+ "Message From Client ID "
+ getID()
+ ": "
+ "Oops. Connection interrupted. Please reconnect your phones.");
}
});
e.printStackTrace();
}
}
private String getID() {
return id.toString();
}
}
}
Here is the full code for the Client class
public class Client extends Activity {
private EditText serverIp;
private EditText chatMsg;
private Button connectPhones;
private Button sendMsg;
private TextView msgFromOtherClients;
private String serverIpAddress = "";
private boolean connected = false;
private boolean willSendMsg = false;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.client);
serverIp = (EditText) findViewById(R.id.server_ip);
connectPhones = (Button) findViewById(R.id.connect_phones);
connectPhones.setOnClickListener(connectListener);
chatMsg = (EditText) findViewById(R.id.chat_msg);
sendMsg = (Button) findViewById(R.id.send_msg);
sendMsg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
willSendMsg = true;
}
});
msgFromOtherClients = (TextView) findViewById(R.id.msg_from_other_clients);
}
private OnClickListener connectListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (!connected) {
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals("")) {
Thread cThread = new Thread(new ClientThread());
cThread.start();
}
}
}
};
public class ClientThread implements Runnable {
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, Server.SERVERPORT);
connected = true;
Thread listener = new Thread(new ClientThreadListener(new Socket(serverAddr, Server.SERVERPORT)));
listener.start();
while (connected) {
if (willSendMsg) {
willSendMsg = false;
try {
Log.d("ClientActivity", "C: Sending command.");
PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
// WHERE YOU ISSUE THE COMMANDS
out.println(chatMsg.getText().toString());
Log.d("ClientActivity", "C: Sent.");
} catch (Exception e) {
Log.e("ClientActivity", "S: Error", e);
}
}
}
socket.close();
Log.d("ClientActivity", "C: Closed.");
} catch (Exception e) {
Log.e("ClientActivity", "C: Error", e);
connected = false;
}
}
}
public class ClientThreadListener implements Runnable {
protected Socket serverSocket = null;
protected String mMsgFromServer;
public ClientThreadListener(Socket serverSocket) {
this.serverSocket = serverSocket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
serverSocket.getInputStream()));
while ((mMsgFromServer = in.readLine()) != null) {
Log.d("MESSAGE FROM SERVER: ", mMsgFromServer);
handler.post(new Runnable() {
#Override
public void run() {
msgFromOtherClients.append('\n'
+ "Message From Server: " + mMsgFromServer);
}
});
}
} catch (Exception e) {
Log.e("ClientListener", "C: Error", e);
connected = false;
}
}
}
}
Your code has some issue that prevents it from working.
As already said in other answers, in your code you are closing the socket output stream right after sending the message to the client. call close() only out of your for message loop. Of course closing the socket in the client will have the same effect as closing it on the server. You must close the sockets only when client and server have finished talking. Closing it while transmitting data it's like hanging up the phone in the middle of a conversation.
Second, you create a new socket on the client side:
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, Server.SERVERPORT);
but then you pass to the listener another, newly created, socket (I suppose this is not intended):
connected = true;
Thread listener = new Thread(new ClientThreadListener(new Socket(serverAddr, Server.SERVERPORT)));
listener.start();
Third, always call flush() on an output stream right after sending data, or the data will likely not be sent (the send methods will just enqueue your data in the sending buffer).
Last (This may not be useful to you since I don't know your ultimate goal), if you need to send and receive on sockets, 90% of the time it's better and easier to do this asinchronously, using separate threads for listening and sending.
If it still doesn't work, add here some output or log trace from logcat.
You need to move the line:
server.broadcastMessage(mMsgFromClient);
inside the while:
while ((mMsgFromClient = in.readLine()) != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.append('\n'
+ "Message From Client ID " + getID()
+ ": " + mMsgFromClient);
}
});
// HERE
Log.d("SERVERTEXT", "Proceed to broadcast");
server.broadcastMessage(mMsgFromClient);
}
Otherwise, you'll only broadcast null.
EDIT: You should make sure that mMsgFromClient is not changed between posting the new Runnable and it actually executing. The best way is to initialize a field in the anonymous class with the current value, and log the value of that field instead.
EDIT2: Unless your server is supposed to close its connection to a client after sending it a broadcast message, you should use out.flush() instead of out.close() in the broadcastMessage method. It's preferrable that client connections are closed after a timeout, or just let the clients disconnect, again with a timeout.
Otherwise, your test will be very limited most of the times: a client connects and sends a message; then it receives its own message and the server closes the connection.
Please try to use AsyncTask in android which will create separate thread for communication with server.

Categories

Resources