Android bug in thread - java

I'm working on an android Quiz app with connection to a server over a socket. On the client side (Android device) I check in a while loop the answers which are given by a server (Java server). The connection and the receiving of the answer all goes good. The problem is that in my class to check for answers there's a bug. To give more information I will include a part of the code here:
public void startClient(){
checkValue = new Thread(new Runnable(){
#Override
public void run() {
try
{
final int PORT = 4444;
final String HOST = "192.168.1.118";
Socket SOCK = new Socket(HOST, PORT);
Log.e("success", "You connected to: " + HOST);
quizClient = new QuizClient(SOCK);
//Send the groupname to the list
PrintWriter OUT = new PrintWriter(SOCK.getOutputStream());
OUT.println(groupName);
OUT.flush();
Thread X = new Thread(quizClient);
X.start();
connected = true;
}
catch(Exception X)
{
Log.e("connection error", "Error: ", X);
}
}
});
checkValue.start();
}
public void testvalue(){
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
while(true){
if(message != null && !message.matches("")){
Thread.sleep(1000);
Log.e("receive", message);
buffer = message;
message = "";
Message msg = new Message();
String textTochange = buffer;
msg.obj = textTochange;
mHandler.sendMessage(msg);
Thread.sleep(3000);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String text = (String)msg.obj;
//call setText here
//String[] myStringArray = new String[];
value.clear();
String[] items = text.split(";");
for (String item : items)
{
value.add(item);
Log.e("message", item);
//System.out.println("item = " + item);
}
if(value.get(0).equals("1")){
questionGroup.setVisibility(View.INVISIBLE);
sendAnswer.setVisibility(View.INVISIBLE);
answer.setVisibility(View.INVISIBLE);
question.setText("");
question.setText(value.get(2));
rad1.setText(value.get(3));
rad2.setText(value.get(4));
rad3.setText(value.get(5));
rad4.setText(value.get(6));
questionGroup.setVisibility(View.VISIBLE);
sendAnswer.setVisibility(View.VISIBLE);
} else if (value.get(0).equals("2")){
questionGroup.setVisibility(View.INVISIBLE);
sendAnswer.setVisibility(View.INVISIBLE);
answer.setVisibility(View.INVISIBLE);
question.setText("");
question.setText(value.get(2));
answer.setVisibility(View.VISIBLE);
sendAnswer.setVisibility(View.VISIBLE);
} else
{
questionGroup.setVisibility(View.INVISIBLE);
sendAnswer.setVisibility(View.INVISIBLE);
answer.setVisibility(View.INVISIBLE);
question.setText(text);
}
}
};
#Override
protected void onStop()
{
if (connected == true){
try {
quizClient.DISCONNECT();
} catch (IOException e) {
e.printStackTrace();
}
}
if(checkValue != null)
{
checkValue.interrupt();
}
super.onStop();
closeApplication();
}
So I make a new instance of this class (where I actually check the incoming stream of data)
public class QuizClient implements Runnable {
//Globals
Socket SOCK;
Scanner INPUT;
Scanner SEND = new Scanner(System.in);
PrintWriter OUT;
public QuizClient(Socket X)
{
this.SOCK = X;
}
public void run()
{
try
{
try
{
INPUT = new Scanner(SOCK.getInputStream());
OUT = new PrintWriter(SOCK.getOutputStream());
OUT.flush();
CheckStream();
}
finally
{
SOCK.close();
}
}
catch(Exception X)
{
Log.e("error", "error: ", X);
}
}
public void DISCONNECT() throws IOException
{
OUT.println("DISCONNECT");
OUT.flush();
SOCK.close();
}
public void CheckStream()
{
while(true)
{
RECEIVE();
}
}
public void RECEIVE()
{
if(INPUT.hasNext())
{
String MESSAGE = INPUT.nextLine();
if(MESSAGE.contains("#?!"))
{
}
else
{
QuizActivity.message = MESSAGE;
Log.e("test", MESSAGE);
}
}
}
public void SEND(String X)
{
OUT.println(X);
OUT.flush();
}
}
So the bug persist I think in the following class:
public void testvalue(){
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
while(true){
if(message != null && !message.matches("")){
Thread.sleep(1000);
Log.e("receive", message);
buffer = message;
message = "";
What I do here is make a thread and check if the "message" is not equals at null. The message come from the other class:
public void RECEIVE()
{
if(INPUT.hasNext())
{
String MESSAGE = INPUT.nextLine();
if(MESSAGE.contains("#?!"))
{
}
else
{
QuizActivity.message = MESSAGE;
Now most of the time this works good but there are 2 problems. When I go out of the page it disconnect from the server (works) I go back on the page and connect again to the server but this time I don't get any values on the screen (receiving is okj but for one of the other reason it does not go good in my handler). Also get an indexoutofboundexception after a time:
question.setText(value.get(2));
A second problem occurs some time while the program runs. There are moments that I also don't get a value on my interface while it correctly receive the input.
So my guess is that my solution of the thread to read in the values is not the best way to handle it. So now I ask to people with more experience what I can do to make this work without major problems? You need to know the connection works and I get the value in my QuizClient class. So the problem need to be in my main class.
My oncreate class:
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
selectgroep = (Spinner) findViewById(R.id.groepen);
questionGroup = (RadioGroup) findViewById(R.id.QuestionGroup);
sendAnswer = (Button) findViewById(R.id.sendAnswer);
rad1 = (RadioButton) findViewById(R.id.radio0);
rad2 = (RadioButton) findViewById(R.id.radio1);
rad3 = (RadioButton) findViewById(R.id.radio2);
rad4 = (RadioButton) findViewById(R.id.radio3);
answer = (EditText) findViewById(R.id.textanswer);
questionGroup.setVisibility(View.INVISIBLE);
sendAnswer.setVisibility(View.INVISIBLE);
answer.setVisibility(View.INVISIBLE);
try {
connect();
} catch (InterruptedException e) {
e.printStackTrace();
}
//Code na het drukken op de knop
startserver = (Button) findViewById(R.id.startserver);
startserver.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startClient();
getID();
testvalue();
}
});
sendAnswer.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Stuur antwoord door en sluit alles af
questionGroup.setVisibility(View.INVISIBLE);
sendAnswer.setVisibility(View.INVISIBLE);
answer.setVisibility(View.INVISIBLE);
answer.setText("");
rad1.setChecked(true);
rad1.setText("");
rad2.setText("");
rad3.setText("");
rad4.setText("");
question.setText("Wachten op server ... ");
}
});
}
Thank you in advance,
Thomas Thooft

Related

How can I send a String through socket from client then get the return from the server?

I am trying to make a simple java android app
I want to send an order from my computer (client) to my android app (server) the the mobile (server) must send the return back to the client (computer)
Client (computer)
public class Main {
public static void main(String[] args) {
Scanner sx = new Scanner(System.in);
String ln = sx.next();
try {
Socket s = new Socket("192.168.2.2", 4040);
s.setSoTimeout(4000);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(ln);
dos.flush();
s.close();
System.out.println("Done....");
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
Server (android app)
public class MainActivity extends Activity {
EditText portfield, ipfield;
LinearLayout player;
SharedPreferences sp;
SharedPreferences.Editor ed;
String myip, myport;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
player = (LinearLayout) findViewById(R.id.player);
portfield = (EditText) findViewById(R.id.portfield);
ipfield = (EditText) findViewById(R.id.ipfield);
sp = getSharedPreferences("okayawalas2423", MODE_PRIVATE);
ed = sp.edit();
myport = sp.getString("myport", null);
myip = sp.getString("myip", null);
runit();
}
public void runit() {
if (myport != null && myip != null) {
final String myport;
final String myip;
startspy();
}
}
public void startspy() {
player.removeAllViews();
Thread th = new Thread(new Runnable() {
public void run() {
eim();
}
});
th.start();
}
public void eim() {
try {
ServerSocket server = new ServerSocket(Integer.parseInt(myport));
say("Server Connected Successfully .... ");
while (true) {
Socket skt = server.accept();
say("The Server Request Has Been Accepted .... ");
DataInputStream dis = new DataInputStream(skt.getInputStream());
String purein = dis.readUTF();
dsay("Data Has Been Sent Right Now To /// and it contains : \n [[[ " + dis.readUTF() + " ]]]");
DataOutputStream dos = new DataOutputStream(skt.getOutputStream());
String outword = doit(purein);
dos.writeUTF(outword);
dos.flush();
dis.close();
dos.close();
skt.close();
}
} catch (Exception e) {
TextView tz = new TextView(this);
tz.setText(e.toString());
player.setGravity(Gravity.CENTER);
player.addView(tz);
}
}
public void stt(View v) {
if (portfield.getText().toString().equals("") || ipfield.getText().toString().equals("")) {
Toast.makeText(this, "Insert All Data !!", Toast.LENGTH_LONG).show();
} else {
ed.putString("myport", portfield.getText().toString());
ed.putString("myip", ipfield.getText().toString());
ed.commit();
startspy();
}
}
public String doit(String p) {
String funRes = "none";
funRes = p;
return funRes;
}
public void say(String s) {
TextView tz = new TextView(this);
tz.setText(s);
player.setGravity(Gravity.CENTER);
player.addView(tz);
}
public void dsay(String s) {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
}
I type the message on the computer (client) when I press ENTER, I get the "Done..." but the android app gets down!!

Android multi threading UI update

I'm trying to run a UDP connection with external equipment. I want it to send a message to the equipment every 3 second and read the response.
I created 3 classes: main, sender and receive.
I open a Runnable for both sender and receive and let them sleep for 3 seconds before continue.
My problem is, when i push the button on the screen, the messages are send and received, however they are not updated on my screen because the update line is not in a loop. How do i tell it to update the screen every 3 second? the code for reading the message and show it, is this:
textViewState.setText(udpReceive.receivedMessage);
Code
public class MainActivity extends AppCompatActivity {
public static TextView textViewState;
public static Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewState = (TextView) findViewById(R.id.textView);
context = getApplicationContext();
}
public void buttonConnect(View v) {
(new Thread(new udpSender())).start();
(new Thread(new udpReceive())).start();
textViewState.setText(udpReceive.receivedMessage);
}
}
Class to send a message:
public class udpSender implements Runnable {
public void run() {
while (true) {
String messageStr = "Hello Android!";
int server_port = 8888;
DatagramSocket s = null;
try {
s = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
InetAddress local = null;
try {
local = InetAddress.getByName("192.168.43.159");
} catch (UnknownHostException e) {
e.printStackTrace();
}
int msg_length = messageStr.length();
byte[] message = messageStr.getBytes();
DatagramPacket p = new DatagramPacket(message, msg_length, local, server_port);
try {
s.send(p);
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Class to receive message from udp
public class udpReceive implements Runnable {
private static final int MAX_UDP_DATAGRAM_LEN = 100;
private static final int UDP_SERVER_PORT = 8888;
public static String receivedMessage;
public void run() {
while (true) {
String message;
byte[] lmessage = null;
lmessage = new byte[MAX_UDP_DATAGRAM_LEN];
DatagramPacket packet = null;
DatagramSocket socket = null;
try {
packet = new DatagramPacket(lmessage, lmessage.length);
socket = new DatagramSocket(UDP_SERVER_PORT);
socket.receive(packet);
message = new String(lmessage, 0, packet.getLength());
receivedMessage = message;
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
In any class that is in another thread, try doing this
Handler handler = new Handler(getActivity().getMainLooper());
handler.post(new Runnable(){
// your TextView goes here
})
Only the UI thread (main thread) can access UI elements
// Your message receiving class
...
message = new String(lmessage, 0, packet.getLength());
final String message_received = new String(lmessage, 0, packet.getLength());
...
MainActivity.context.runOnUiThread(new Runnable() {
#Override
public void run() {
MainActivity.textViewState.setText(message_received);
}
});
...
I found a solution based on both of your answers :) Thank you
MainActivity class:
public static Handler UIHandler;
static {
UIHandler = new Handler(Looper.getMainLooper());
}
public static void runOnUI(Runnable runnable) {
UIHandler.post(runnable);
}
receive class
MainActivity.runOnUI(new Runnable() {
public void run() {
MainActivity.textViewState.setText(message_received);
}
});

Service Socket Disconnect on Background->Foreground switch

I am writing an IRC Client. The socket connection to the IRC Server is handled via a service. I have managed to stabilize all the UI elements of the Activities in question during the orientation change, but somehow the socket that is maintained by the service is being closed during the change.
Here is what I believe to be the relevant code. Please let me know if you need to see more.
//This is the Service in question
public class ConnectionService extends Service{
private BlockingQueue<String> MessageQueue;
public final IBinder myBind = new ConnectionBinder();
public class ConnectionBinder extends Binder {
ConnectionService getService() {
return ConnectionService.this;
}
}
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
private IRCServer server;
private WifiManager.WifiLock wLock;
private Thread readThread = new Thread(new Runnable() {
#Override
public void run() {
try {
String line;
while ((line = reader.readLine( )) != null) {
if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
queueMessage(line);
}
}
catch (Exception e) {}
}
});
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(MessageQueue == null)
MessageQueue = new LinkedBlockingQueue<String>();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return myBind;
}
#Override
public boolean stopService(Intent name) {
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.stopService(name);
}
#Override
public void onDestroy()
{//I put this here so I had a breakpoint in place to make sure this wasn't firing instead of stopService
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDestroy();
}
public void SendMessage(String message)
{
try {
writer.write(message + "\r\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine()
{
try {
if(!isConnected())
return null;
else
return MessageQueue.take();
} catch (InterruptedException e) {
return "";
}
}
public boolean ConnectToServer(IRCServer newServer)
{
try {
//create a new message queue (connecting to a new server)
MessageQueue = new LinkedBlockingQueue<String>();
//lock the wifi
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "LockTag");
wLock.acquire();
server = newServer;
//connect to server
socket = new Socket();
socket.setKeepAlive(true);
socket.setSoTimeout(60000);
socket.connect(new InetSocketAddress(server.NAME, Integer.parseInt(server.PORT)), 10000);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//run basic login scripts.
if(server.PASS != "")
SendMessage("PASS " + server.PASS);
//write nickname
SendMessage("NICK " + server.NICK);
//write username login
SendMessage("USER " + server.NICK + " 0 * :Fluffy IRC");
String line;
while ((line = reader.readLine( )) != null) {
if (line.indexOf("004") >= 0) {
// We are now logged in.
break;
}
else if (line.indexOf("433") >= 0) {
//change to alt Nick
if(!server.NICK.equals(server.ALT_NICK) && !server.ALT_NICK.equals(""))
{
server.NICK = server.ALT_NICK;
SendMessage("NICK " + server.NICK);
}
else
{
queueMessage("Nickname already in use");
socket.close();
return false;
}
}
else if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
{
queueMessage(line);
}
}
//start the reader thread AFTER the primary login!!!
CheckStartReader();
if(server.START_CHANNEL == null || server.START_CHANNEL == "")
{
server.WriteCommand("/join " + server.START_CHANNEL);
}
//we're done here, go home everyone
} catch (NumberFormatException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
private void queueMessage(String line) {
try {
MessageQueue.put(line);
} catch (InterruptedException e) {
}
}
public boolean isConnected()
{
return socket.isConnected();
}
public void CheckStartReader()
{
if(this.isConnected() && !readThread.isAlive())
readThread.start();
}
}
//Here are the relevant portions of the hosting Activity that connects to the service
//NOTE: THE FOLLOWING CODE IS PART OF THE ACTIVITY, NOT THE SERVICE
private ConnectionService conn;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn = ((ConnectionService.ConnectionBinder)service).getService();
Toast.makeText(main_tab_page.this, "Connected", Toast.LENGTH_SHORT)
.show();
synchronized (_serviceConnWait) {
_serviceConnWait.notify();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
conn = null;
}
};
#Override
protected void onSaveInstanceState(Bundle state){
super.onSaveInstanceState(state);
state.putParcelable("Server", server);
state.putString("Window", CurrentTabWindow.GetName());
unbindService(mConnection);
}
#Override
protected void onDestroy()
{
super.onDestroy();
if(this.isFinishing())
stopService(new Intent(this, ConnectionService.class));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab_page);
localTabHost = (TabHost)findViewById(R.id.tabHostMain);
localTabHost.setup();
localTabHost.setOnTabChangedListener(new tabChange());
_serviceConnWait = new Object();
if(savedInstanceState == null)
{//initial startup, coming from Intent to start
//get server definition
server = (IRCServer)this.getIntent().getParcelableExtra(IRC_WINDOW);
server.addObserver(this);
AddTabView(server);
startService(new Intent(this, ConnectionService.class));
}
else
{
server = (IRCServer)savedInstanceState.getParcelable("Server");
String windowName = savedInstanceState.getString("Window");
//Add Needed Tabs
//Server
if(!(windowName.equals(server.GetName())))
AddTabView(server);
//channels
for(IRCChannel c : server.GetAllChannels())
if(!(windowName.equals(c.GetName())))
AddTabView(c);
//reset each view's text (handled by tabChange)
if(windowName.equals(server.GetName()))
SetCurrentTab(server.NAME);
else
SetCurrentTab(windowName);
ResetMainView(CurrentTabWindow.GetWindowTextSpan());
//Rebind to service
BindToService(new Intent(this, ConnectionService.class));
}
}
#Override
protected void onStart()
{
super.onStart();
final Intent ServiceIntent = new Intent(this, ConnectionService.class);
//check start connection service
final Thread serverConnect = new Thread(new Runnable() {
#Override
public void run() {
if(!BindToService(ServiceIntent))
return;
server.conn = conn;
conn.ConnectToServer(server);
server.StartReader();
if(server.START_CHANNEL != null && !server.START_CHANNEL.equals(""))
{
IRCChannel chan = server.FindChannel(server.START_CHANNEL);
if(chan != null)
{
AddTabView(chan);
}
else
{
server.JoinChannel(server.START_CHANNEL);
chan = server.FindChannel(server.START_CHANNEL);
AddTabView(chan);
}
}
}
});
serverConnect.start();
}
private boolean BindToService(Intent ServiceIntent)
{
int tryCount = 0;
bindService(ServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
while(conn == null && tryCount < 10)
{
tryCount++;
try {
synchronized (_serviceConnWait) {
_serviceConnWait.wait(1500);
}
}
catch (InterruptedException e) {
//do nothing
}
}
return conn != null;
}
Im not entirely certain what I am doing wrong there. Obviously there's something I'm missing, haven't found yet, or haven't even thought to check. What happens though is that after the orientation change my Send command gives me this message and nothing happens:
06-04 22:02:27.637: W/System.err(1024): java.net.SocketException: Socket closed
06-04 22:02:27.982: W/System.err(1024): at com.fluffyirc.ConnectionService.SendMessage(ConnectionService.java:90)
I have no idea when the socket is getting closed, or why.
Update
I have changed the code so that rather than binding to the service and using that to start it, instead I call startService and stopService at appropriate points as well as binding to it, on the thought that the service was being destroyed when the binding was lost. This is working exactly like it was before I changed it. The socket still closes on an orientation change, and I have no idea why.
Update :- Code and description
I added the code changes recently made for Start/Stop service and START_STICKY. I also recently read a very good article explaining how the orientation change process flow works and why its NOT a bad idea to add the android:configChanges="orientation|screenSize" line to your manifest. So this fixed the orientation issue, but its still doing the same thing if I put the activity into background mode, and then bring it back to the foreground. That still follows the same Save/Destroy/Create process that the orientation does without that manifest line...and it still closes my socket, and I still don't know why.
I do know that it doesn't close the socket until the re-create process...I know this because the message queue will display messages that were received while the app was in the background, but once I bring it back forward it closes the socket and nothing else can be sent or received.
'Socket closed' means that you closed the socket and then continued to use it. It isn't a 'disconnect'.
You need to put something into that catch block. Never just ignore an exception. You might get a surprise when you see what the exception actually was.
NB Socket.isConnected() doesn't tell you anything about the state of the connection: only whether you have ever connected the Socket. You have, so it returns true.

Android Socket sending data to WPF application

So i have a registration Android app that in main activity creates a socket connection on create opensocket(). Everything runs perfectly on the first submit, the debugger out put looks great and it sends/recieves data back from my WPF app. Now It goes to a thanks activity which onclick leads back to my mainactivity. Now when i hit submit, it works fine, but is showing its hitting my socket methods twice (only inserts the records once on my WPF app) , and so on as many times i submit. I realize i'm not closing or reusing my socket connection correctly?! I've tried several things, but can't seem to get this to either reuse the same opensocket instance or can't just close and reopen on reload. I'm quite new to android and sockets all together, any help is greatly appreciated!
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
settingsCheck();
openSocket();
sett.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
launchSettings();
}
});
mainLogo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
RefreshMain();
}
});
btn_register.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
tv_errors.setText("");
errorMsg = "";
nameCheck(et_lName.getText().toString(),et_fName.getText().toString());
emailCheck(et_email.getText().toString());
partnerCheck();
mobileCheck(et_mobile.getText().toString());
if (SocketHandler.SocketConnected){
if(errorMsg == ""){
//tv_errors.setText("");
if(checkForSD() == true){
sendRegistrantInfo(et_fName.getText() + "," + et_lName.getText() + "," + et_email.getText() + "," + et_mobile.getText() + "," + et_partEmail.getText() + "," + cb_terms1.isChecked() + "," + cb_terms2.isChecked() );
}
else{
tv_errors.setText("**Please insert an SD Card.");
}
}
else{
//tv_errors.setText(errorMsg);
}
}
else
{
connectionStatus.setText("Connection Error.");
tv_errors.setText("**Connection lost, please try again.");
//openSocket();
}
}
});
}
public void RefreshMain()
{
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
public void launchLogin()
{
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}//end launchLogin
public void launchSettings()
{
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
}//end launchSettings
public void settingsCheck()
{
SharedPreferences settings = getSharedPreferences("prefs",MODE_PRIVATE);
String currentIP = settings.getString("IPSetting", "");
String currentPort = settings.getString("PORTSetting", "");
currentMem = settings.getString("SDSize", "");
if (currentIP == "" || currentPort == ""){
Intent myIntent = new Intent(this,SettingsActivity.class);
startActivity(myIntent);
}
}//end settingsCheck()
public void launchRingDialog(String id) {
final String idYo = id;
final ProgressDialog ringProgressDialog = ProgressDialog.show(MainActivity.this, "Formatting SD Card","Formatting SD Card, please wait this could take several minutes...", true);
new Thread(new Runnable() {
#Override
public void run() {
try {
fileToSD(idYo);
Thread.sleep(10000);
} catch (Exception e) {
}
ringProgressDialog.dismiss();
}
}).start();
}
public boolean checkForSD()
{
String root = "/storage/removable/sdcard1/";
double memInGigs = round(sizeMatters(root),2);
if(memInGigs >0){
return true;
}
else
{
return false;
}
}
private double sizeMatters(String path)
{
StatFs stat = new StatFs(path);
double availSize = (double)stat.getAvailableBlocks() * (double)stat.getBlockSize();
double ingigs = availSize/ 1073741824;
return ingigs;
}//end sizeMatters()
private void sendRegistrantInfo(String reg){
_sh.sendMessage(reg);
}
private void openSocket(){
_sh = new SocketHandler();
_sh.setSocketHandlerListener(this);
SharedPreferences settings = getSharedPreferences("prefs",MODE_PRIVATE);
String currentIP = settings.getString("IPSetting", "");
String currentPort = settings.getString("PORTSetting", "");
_sh.open(currentIP, currentPort);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
}
#Override
public void onSocketConnected() {
Log.v(TAG, "onSocketConnected");
connectionStatus.setText("CONNECTED");
}
#Override
public void onSocketData(String msg) {
Log.v(TAG, "onSocketData - " + msg );
int usrID = Integer.parseInt(msg.trim());
if (msg != null & usrID > 0){
launchRingDialog(msg);
Intent intent = new Intent(this, ThanksActivity.class);
startActivity(intent);
}
else if(msg.trim().equals("-2") == true)
{
tv_errors.setText("**This email has already been registered for this event, please click Already Registered button to sign in.");
}
else{
tv_errors.setText("**Error, Please try submitting again.");
errorMsg = "-1";
}
}
#Override
public void onSocketDisconnected() {
Log.v(TAG, "onSocketDisconnected");
connectionStatus.setText("DISCONNECTED");
}
public class SocketHandler {
Socket sc;
public static boolean SocketConnected = false;
private static ClientThread cThread;
public String prefsFile = "prefs";
public String port = "8888";
public String ip = "192.168.1.4";
private String TAG = "SocketHandler";
protected SocketHandlerListener socketHandlerListener;
public interface SocketHandlerListener{
public void onSocketConnected();
public void onSocketData(String msg);
public void onSocketDisconnected();
}
public SocketHandler(){
}
public void setSocketHandlerListener(SocketHandlerListener shl){
socketHandlerListener = shl;
}
public void open(String ip, String port){
this.ip = ip;
this.port = port;
cThread = new ClientThread();
try{
cThread.start();
}catch (Exception ex){
Log.v(TAG, "Error connecting to socket");
}
}
public void close(){
if (cThread != null){
if (cThread.socket != null){
try {
cThread.socket.close();
} catch (Exception e) {
Log.v(TAG, "Error closing socket");
}
cThread.socket = null;
}
}
}
public void sendMessage(String msg){
cThread.sendMessage(msg);
}
public void messageRecieved(String msg){
dispatchSocketData(msg);
}
private void dispatchSocketConnected(){
if (socketHandlerListener != null){
socketHandlerListener.onSocketConnected();
}
}
private void dispatchSocketDisconnected(){
if (socketHandlerListener != null){
socketHandlerListener.onSocketDisconnected();
}
}
private void dispatchSocketData(String msg){
if (socketHandlerListener != null){
socketHandlerListener.onSocketData(msg);
}
}
public class ClientThread extends Thread {
public Socket socket;
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(ip);
Log.v(TAG, "C: Connecting..." + ip + ":" + port);
socket = new Socket(serverAddr, Integer.parseInt(port));
socket.setSoTimeout(0);
socket.setKeepAlive(true);
SocketConnected = true;
handler.post(new Runnable() {
#Override
public void run() {
dispatchSocketConnected();
}
});
// BLOCKING THE THREAD
while (SocketConnected) {
InputStream in = socket.getInputStream();
byte[] buffer = new byte[4096];
int line = in.read(buffer, 0, 4096);
while (line != -1) {
byte[] tempdata = new byte[line];
System.arraycopy(buffer, 0, tempdata, 0, line);
final String data = new String(tempdata);
handler.post(new Runnable() {
#Override
public void run() {
messageRecieved(data);
SocketConnected = false;
}
});
line = in.read(buffer, 0, 4096);
}
// break;
}
socket.close();
Log.v("Socket", "C: Closed.");
handler.post(new Runnable() {
#Override
public void run() {
dispatchSocketDisconnected();
}
});
SocketConnected = false;
} catch (Exception e) {
Log.v("Socket", "C: Error", e);
handler.post(new Runnable() {
#Override
public void run() {
dispatchSocketDisconnected();
}
});
SocketConnected = false;
}
}
Handler handler = new Handler();
public void sendMessage(String msg){
if (socket != null){
if (socket.isConnected()){
PrintWriter out;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), false);
out.print(msg);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}

Socket communication between two apps on Android

I have got huge problem with my Android app and I would like to ask you for help.
I am currently writing Android Clietn-Server app using sockets. I have found lots of tutorils on the Internet and from them I have created basics for my project. However, all tutorials are only for one message send and that's all. I need to send more of them so I've been trying to modify it.
This are code fragments responsible for server and client. The rest is not important at this time.
Server:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverStatus = (TextView) findViewById(R.id.server_status);
recivedMsg = (TextView)findViewById(R.id.rec_msg);
SERVERIP = getLocalIpAddress();
Thread fst = new Thread(new ServerThread());
fst.start();
}
public class ServerThread implements Runnable {
public void run() {
try {
if (SERVERIP != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Listening on IP: " + SERVERIP);
}
});
serverSocket = new ServerSocket(SERVERPORT);
while (true) {
// listen for incoming clients
Socket client = serverSocket.accept();
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Connected." + System.getProperty("line.separator"));
}
});
try {
line = null;
while (connected) {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
if((line = in.readLine())!=null)
{
Log.d("ServerActivity", line);
handler.post(new Runnable() {
#Override
public void run() {
if(recivedMsg.equals("CLOSE"))
{
recivedMsg.append("CLOSE socket");
connected = false;
}
else
{
recivedMsg.append("MSG: " + line + System.getProperty("line.separator"));
}
// do whatever you want to the front end
// this is where you can be creative
}
});
}
else
{
recivedMsg.append("empty" + System.getProperty("line.separator"));
}
}
break;
} catch (Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Oops. Connection interrupted. Please reconnect your phones.");
}
});
e.printStackTrace();
}
}
} else {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Couldn't detect internet connection.");
}
});
}
} catch (Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Error");
}
});
e.printStackTrace();
}
}
}
Client
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverIp = (EditText) findViewById(R.id.server_ip);
connectPhones = (Button) findViewById(R.id.connect_phones);
sendField = (EditText) findViewById(R.id.send_field);
sendMsg = (Button) findViewById(R.id.msg_send);
connectPhones.setOnClickListener(connectListener);
sendMsg.setOnClickListener(sendMessage);
}
#Override
protected void onStop() {
super.onStop();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = "CLOSE";
out.write(outMsg);
out.flush();
// make sure you close the socket upon exiting
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private OnClickListener connectListener = new OnClickListener() {
#Override
public void onClick(View v) {
serverIpAddress = serverIp.getText().toString();
runTcpConnection();
sendMessageToServer("Msg");
}
};
private OnClickListener sendMessage = new OnClickListener() {
#Override
public void onClick(View v) {
sendMessageToServer(sendField.getText().toString());
}
};
private void runTcpConnection() {
try {
s = new Socket(serverIpAddress, SERVERPORT);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = "TCP connecting to " + SERVERPORT + System.getProperty("line.separator");
out.write(outMsg);
out.flush();
Log.i("TcpClient", "sent: " + outMsg);
SystemClock.sleep(10);
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
};
public void sendMessageToServer(String str) {
try {
s = new Socket(serverIpAddress, SERVERPORT);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = str + System.getProperty("line.separator");
out.write(outMsg);
out.flush();
Log.i("TcpClient", "sent: " + outMsg);
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("", "hello222");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("", "hello4333");
}
}
For now devices connect correctly. Moreover They are sending the first connection messages (those in OnClickListener connectListener). The problem is that when I am trying to send another message using sendMessageToServer it is impossible. Those messages shows only after client activity is destroyed.
Very interesting is that without SystemClock.sleep(10); listener runTcpConnection() behave strange. Only 'Connected.' displays on server.
Can someone tell me what I have to do to be able to send messages normally?
EDIT:
This are things that I have found:
If I am at the connection sending more messages than all are empty (null) and after the second one connection error shows - please reconnect phones
If I am at the connection sending more messages without s.close line in sendMessageToServer only one message is passing through. No error is displayed after it.
The message form runTcpConnection shows always (except when in this function is no SystemClock.sleep(10))
Hope it will help someone to diagnose my error.
As I see, you create a new socket whenever user click button send, right? I recommend you should init it only one time when user click connect, then you use it in send click event ( because this is TCP, you will disconnect to server if you create new instance of socket)
So, you should remove these lines in sendMessageToServer :
s = new Socket(serverIpAddress, SERVERPORT);
s.close();
and this line in runTcpConnection
s.close();
Socket should close whenever you don't want communicate with the server (onstop is an example, or when change activity...)
Also you should create only one instance of BufferedWriter too.
Hope this help.

Categories