I am connecting two Android Devices P2P using the following code. The problem is that when the server receives data from client its Thread/Runnable doesn't stop.
Please suggest me a way to stop/forced this to go in an infinite loop.
Following Is the piece of code I am using for my Server Activity :
public class ServerThread implements Runnable {
private volatile boolean keepGoing = true;
public void requestStop() {
keepGoing = false;
}
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.");
}
});
try {
BufferedReader in = new BufferedReader(new
InputStreamReader(client.getInputStream()));
line = null;
while ((line = in.readLine()) != null) {
Log.d("ServerActivity", line);
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText(line);
Log.d("IP recevied", line);
requestStop();
//finish();
//Intent i = new Intent(ServerActivity.this,
//ClientActivity.class);
//startActivity(i);
//serverStatus.setText(line);
// do whatever you want to the front end
// this is where you can be creative
}
});
}
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();
}
}
}
EDIT:
while (keepGoing) {
// listen for incoming clients
Socket client = serverSocket.accept();
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Connected.");
}
});
try {
BufferedReader in = new BufferedReader(new
InputStreamReader(client.getInputStream()));
line = null;
while (((line = in.readLine()) != null) && keepGoing) {
Log.d("ServerActivity", line);
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText(line);
Log.d("IP recevied", line);
requestStop();
//finish();
//Intent i = new Intent(ServerActivity.this,
//ClientActivity.class);
//startActivity(i);
//serverStatus.setText(line);
// do whatever you want to the front end
// this is where you can be creative
}
});
}
I think the problem is that even though you signal the server to stop, it's still stuck in the call to serverSocket.accept();, waiting for other clients to connect. What you should do is also close the socket in the stop method:
public void requestStop() {
keepGoing = false;
serverSocket.close();
}
to force the code to throw an IOException and then recheck the while condition and exit.
Why did you comment the line
//finish();
once the connection is established?
Since you never finish once you are connected you have an infinite loop
Related
So I am working on an app that is involving sockets. Multiple strings is sent through the socket, the receiving end receives it, and updates the RecyclerView correspondingly. It's working fine, that is until the app crashes / restarts. I do not know what happens, but there's this app called XRecorder on Play Store and everytime I use the screenshot function- my app restarts. Now when I send a message through the socket, it receives the message but it doesn't update the RecyclerView? The Toast appears that's why I know it is received. And it updates as well when I call removeItem()
Here's my code :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
serverAsync.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private class ServerAsync extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try {
serverSocket = new ServerSocket(serverPort);
while (true) {
Socket client = serverSocket.accept();
isConnected = client.isConnected();
if (isConnected) {
try {
handler.post(new Runnable() {
#Override
public void run() {
updateStatusUI();
}
});
Entry entry = new Entry();
String inputLine;
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while ((inputLine = in.readLine()) != null) {
StringBuilder sb = new StringBuilder();
String message = inputLine;
sb.append(message);
entry.add(sb.toString());
}
//READ NEW ENTRIES
handler.post(new Runnable() {
#Override
public void run() {
splitOrder(entry);
saveArrayList();
}
});
in.close();
handler.post(new Runnable() {
#Override
public void run() {
entryAdapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "In has closed :" + client.getRemoteSocketAddress(), Toast.LENGTH_SHORT).show();
updateStatusUI();
}
});
} catch (Exception e) {
Log.e("TEST", e.getMessage(), e);
}
} else {
Toast.makeText(getApplicationContext(), "Client :" + client.getRemoteSocketAddress()+" has DISCONNECTED", Toast.LENGTH_SHORT).show();
handler.post(new Runnable() {
#Override
public void run() {
updateStatusUI();
}
});
}
}
} catch (Exception e) {
Log.e("UHE", e.getMessage(), e);
}
return null;
}
}
public void removeItem(int position) {
entryAdapter.notifyDataSetChanged();
}
I've tried resetting the adapter for the RecyclerView, but it just wouldn't work. I also noticed that everytime I the app crashes and restart, I am getting the java.net.BindException: bind failed: EADDRINUSE (Address already in use)
Pointing to the creation of my serverSocket (serverSocket = new ServerSocket(serverPort)
Could this be the reason why the RecyclerView won't update? The ArrayList updates just fine with the incoming messages, but not the view.
In my application i have timer for some works.
When my application running after some time my application freeze and not work any View !
In this timer every 500ms i emit socket.io
My Codes:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
socketPingTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (isSendSocketPing) {
checkSocketPingTimer += startSocketPingTimer;
if (checkSocketPingTimer == sendSocketPingTimer) {
currentTimerForSocket = System.currentTimeMillis();
try {
detailSocketUtils.getSendRTTforPing(currentTimerForSocket + "");
} catch (Exception e) {
}
}
//Show ping (from search)
Constants.currentActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (isShownPing) {
detailToolbar_ping.setVisibility(View.VISIBLE);
if (checkSocketPingTimer > 500) {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.RED);
} else {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.GREEN);
}
} else {
detailToolbar_ping.setVisibility(View.GONE);
}
}
});
socketPing = checkSocketPingTimer;
}
}
}, 500, startSocketPingTimer);
}
});
How can i run this timers in another thread and not freeze my app ?
It should be something similar to this code:
class MyActivity extends Activity
{
private void executeLoop()
{
Handler myHandler = new Handler()
{
public void handleMessage(Message msg)
{
if (isShownPing)
{
detailToolbar_ping.setVisibility(View.VISIBLE);
if (checkSocketPingTimer > 500) {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.RED);
} else {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.GREEN);
}
} else
{
detailToolbar_ping.setVisibility(View.GONE);
}
}
}
socketPingTimer.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
if (isSendSocketPing)
{
checkSocketPingTimer += startSocketPingTimer;
if (checkSocketPingTimer == sendSocketPingTimer) {
currentTimerForSocket = System.currentTimeMillis();
try {
detailSocketUtils.getSendRTTforPing(currentTimerForSocket + "");
} catch (Exception e) {
}
}
myHandler.sendEmptyMessage();
socketPing = checkSocketPingTimer;
}
}
}, 500, startSocketPingTimer);
}
}
private void startTimerAtFixRate() {
android.os.Handler handler = new android.os.Handler();
Runnable updateTimerThread = new Runnable() {
public void run() {
//write here whatever you want to repeat
// Like I called Log statement
// After every 1 second this below statement will be executed
Log.e("CALLED-->", "TRUE");
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(updateTimerThread, 100);
}
I have an Android App which constantly auto updating a list of data from the App's SQLite which an ArrayAdapter is used for handling the data, So for this I've made another thread or handler from the onCreate method of the Acitivity, and inside it's code there's a continuous loop for updating then waiting (or sleeping the thread for a moment, ex/ 10 sec), There are two problems involved:
1- Only the UI thread can touch it's views (though I only touched ArrayAdapter if it counts as a View).
2- Once the other thread starts to run, The UI thread seems to stuck in it, and won't update even the first UI update (complete white).
codes for the autoUpdate() method: (which is called on the last line of the UI onCreate method):
public void startAutoUpdateLogData(final int milliseconds){
continueAutoUpdate = true;
new Thread(){
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.v("updating..", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
}.start();
}
OR:
public void startAutoUpdateLogData2(final int milliseconds){
continueAutoUpdate = true;
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.e("updating...", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
OR
public void startAutoUpdateLogData3(final int milliseconds){
continueAutoUpdate = true;
final Handler handler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
Neither of these work.
You can do many ways. But this one will be more closer solution to what you have done.
private void runThread() {
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
After trying various stuff, I finally found the solution: Anytime you have some long-run tasks to perform, you can assign a new Java thread to execute it, but when there's a need to update the UI from that thread, which can't be directly accessing any components of the UI, So in that case you only need to wrap the code with runOnUiThread() inside the other thread. ex/
private void startAutoUpdateLogData(final int milliseconds) {
final Handler handler = new Handler();
continueAutoUpdate = true;
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("updating...", "");
updateLogFromDatabase();
}
});
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
I am creating a small game over wifi-direct through sockets on Android. On the client receiving thread I am listening for Messages from the other device:
class ReceivingThread implements Runnable {
#Override
public void run() {
BufferedReader input;
try {
input = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
while (!Thread.currentThread().isInterrupted()) {
final String messageStr = input.readLine();
if (messageStr != null) {
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, messageStr, Toast.LENGTH_LONG).show();
activity.handleMessage(messageStr);
}
});
} else {
break;
}
}
input.close();
} catch (IOException e) {
}
}
}
And the toast shows the message just fine, but the app crashes on activity.handleMessage(). This is what the method does (cut it down just to one case, just for the point of the method):
public void handleMessage(String msg){
switch(msg){
case "1":
Button temp = (Button) findViewById(btn1);
if(isOwner) {
temp.setText("O");
} else {
temp.setText("X");
}
temp.setEnabled(false);
break;
case "You Lose":
TextView textBox = (TextView) findViewById(R.id.textBox);
textBox.setText("You Lose!");
}
}
And the message I get is:
java Looper.prepare() wasn't called on this thread.
Instead of activity.handleMessage(messageStr); you need to send it as a message to the handler, so handleMessage will execute in the loop.
Bundle data = new Bundle();
data.putString("MESSAGE_KEY", messageStr);
Message msg = new Message();
msg.setData(data);
activity.sendMessage(msg);
So you will receive in handleMessage of the Handler the Message, to extract the String you do message.getData().getString("MESSAGE_KEY");
Create UI thread inside handler and try to perform the UI operation.
new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
And how should i solve it ?
This is my button click method that i call it from inside onCreate:
public void addListenerOnButton()
{
btnClick = (Button) findViewById(R.id.checkipbutton);
btnClick.setOnClickListener(new OnClickListener()
{
byte[] response = null;
#Override
public void onClick(View arg0)
{
text = (TextView) findViewById(R.id.textView2);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
for (int i = 0; i < ipaddresses.length; i++)
{
try
{
response = Get(ipaddresses[i]);
if (response == null)
{
text.setText("Connection Failed: " + generateRunnablePrinter(i));
}
}
catch (Exception e)
{
String err = e.toString();
}
if (response != null)
{
try
{
final String a = new String(response, "UTF-8");
text.post(new Runnable()
{
#Override
public void run()
{
text.setText(a);
}
});
iptouse = ipaddresses[i].substring(0, 26);
connectedtoipsuccess = true;
Logger.getLogger("MainActivity(inside thread)").info(a);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
Logger.getLogger("MainActivity(inside thread)").info("encoding exception");
}
Logger.getLogger("MainActivity(inside thread)").info("test1");
break;
}
else
{
}
}
}
});
t.start();
}
});
}
At this place in the method inside the FOR loop the variable 'i' should be final:
text.setText("Connection Failed: " + generateRunnablePrinter(i));
But since 'i' is also the variable of the FOR loop i can't make it final.
So i added the method : generateRunnablePrinter
private Runnable generateRunnablePrinter(final int value)
{
return new Runnable() {
public void run()
{
text.setText("Connection Failed: " + ipaddresses[value]);
}
};
}
But now using this method I'm getting the exception:
ViewRootImpl$CalledFromWrongThreadException
You can't change the UI "text of the TextView" from another thread so you can try AsyncTask to do the work in the background in doInBackground() method then change the UI in the method onPostExecute().
Check out the AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Since you're adjusting your UI, you'll need to run it from the UI thread. I'd recommend this function:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your code here...
}
});
If you're calling it from anywhere else but an Activity, you'll need to either pass down the activity or get the activity using getActivity() (i.e. from a fragment), and then call the function from the activity, i.e. getActivity().runOnUiThread() { ... }