Button onClick() not working when thread is running - java

I am struggling with setting the text of a TextView, so I am now trying to do it with a button push, but when I start the thread from the button readWeight the button updateButton does not work.
Here are my two button onClick methods:
readWeight.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
inputWindow.setText("helloooooooo worldddddd");
//connector.run();
System.out.println("********** PRINTING **********");
// readWeight.setVisibility(View.INVISIBLE);
}
});
updateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
System.out.println("!!!!!!!!!!!!!!!"+weight+"!!!!!!!!!!!!!!!");
inputWindow.setText(weight);
}
});
and here is my method that starts the thread, this method is in another class:
public void run() {
new Handler().post(new Runnable() {
#Override
public void run() {
// Always cancel discovery because it will slow down a connection
//Log.d("workkkkkk","$$$$$$$$$$$$$$$$****** printingggggg ******$$$$$$$$$$$$$$$$");
int counter = 0;
while (true) {
counter++;
try {
output = "";
//read the data from socket stream
//mmInStream != null && counter%10000000 == 1
if (mmInStream != null) {
mmInStream.read(buffer);
for (byte b : buffer) {
char c = (char) b;
if (c >= ' ' && c < 'z') {
// System.out.print(c);
output += c;
}
}
System.out.println();
Intent intent = new Intent();
intent.setAction("com.curie.WEIGHT_RECEIVED");
intent.putExtra("Output",output);
if (counter % 10 == 0) {
System.out.println(counter);
//InputActivity.setInputWindowText(output);
LocalBroadcastManager.getInstance(InputActivity.getContext()).sendBroadcastSync(intent);
}
}
// Send the obtained bytes to the UI Activity
} catch (IOException e) {
//an exception here marks connection loss
//send message to UI Activity
break;
}
}
}
Any help would be very appreciated! thank you.

When you use
Handler.post()
It runs in UI thread, so if it is long action it will block all interface.
To avoid it you should run it in another thread. If you don't want to use something complicated you can try this:
mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run () {
mHandler.post(new Runnable() {
#Override
public void run () {
// place your action here
}
});
}
}).start();

Related

Thread isn't interrupted after even after calling interrupt method

I have an activity with 3 buttons: create, start and cancel. Button create creates a new thread, button start runs it and button cancel stops this thread. And my problem is that thread isn't interrupted after calling interrupt method (this action is performed after clicking on cancel button). I know, that in my thread I should check if thread is interrupted or no. I added it, but interrupting still doesn't work. Here's my code:
private View.OnClickListener listener = new View.OnClickListener() {
#SuppressLint("HandlerLeak")
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.create_button:
thread = new Thread(new Runnable() {
#Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
}
}, 500*i);
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
new Handler().postDelayed(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Done!");
}
},(i+1)*500);
}
});
break;
case R.id.start_button:
thread.run();
break;
case R.id.cancel_button:
thread.interrupt();
Log.i(getClass().getSimpleName(), "Cancel Button clicked");
break;
}
}
};
So, why thread isn't interrupted and how can I solve this problem?
Your thread is quickly adding 11 tasks (10 + the last one) to this handler you're creating and then dying. These tasks have a delay, and then the message queue will take care of running the 10 + 1 runnables. To do what you're trying to do you should make the thread to wait 500ms between each loop.
Something similar to this:
thread = new Thread(new Runnable() {
#Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText("Done!");
}
});
}
});
There are many problems with your code
Problem 1: When users click on Create button, you create a new thread, it is not expected behavior as you want, so just create a new thread if it is not created yet or terminated.
Problem 2: When users click on Start button
thread.run();
This line does not start the thread, it just executes the code in run method on calling thread, in this case main/UI thread. To start a thread you must use start method. Make sure you start the thread if it is has been created.
Problem 3: When users click on Cancel button
thread.interrupt();
Because there is no thread started so this line will do nothing.
Problem 4: From your description, you want to use a thread to increase counter on a TextView from 0 to 9 each 0.5 second, then display "Done". Your code is incorrect and contains many redundant.
Solution: You can following this code.
private View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.create_button:
// Only create a new thread if it is not created or it is terminated.
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
final int finalI = i;
// This will post a message to main/UI thread.
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
// Sleep current thread in 0.5 second before running next step.
Thread.sleep(500);
}
// Display Done after finishing counter.
textCounter.post(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Done!");
}
});
} catch (InterruptedException e) {
// Display Cancelled if the current thread is cancelled.
textCounter.post(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Cancelled!");
}
});
}
}
});
} else {
Toast.makeText(MainActivity.this,
"Thread is already created. No need to create anymore.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.start_button:
// Start thread if it is created.
if (thread != null && thread.getState() == Thread.State.NEW) {
thread.start();
} else {
Toast.makeText(MainActivity.this,
"Thread is not created yet or it is running.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.cancel_button:
// Cancel the thread if it is running.
if (thread != null && thread.isAlive()) {
thread.interrupt();
} else {
Toast.makeText(MainActivity.this,
"Thread is not running yet.",
Toast.LENGTH_SHORT)
.show();
}
break;
}
}
};

How to use delay functions in Android Studio?

I want to send a character with Bluetooth. The code works perfectly when there is only a single character.But I want to use a delay function between the two codes.
I want to enter any number with EditText and the app will take that number and do EditText/44. That is what I want to wait between 2 codes
Finally work.. Thanks guys. :)
I moved a,b,c inside setOnClick.. ;
kileri = (Button) findViewById(R.id.kileri);
final EditText value1 = (EditText) findViewById(R.id.textkont);
assert value1 != null;
value1.setText("0");
btAdapter = BluetoothAdapter.getDefaultAdapter();
checkBTState();
kileri.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
int a = Integer.parseInt(value1.getText().toString());
int b = a / 44;
int c = b * 1000;
sendData("F");
try {
Thread.sleep(c);
} catch (Exception e) {
e.printStackTrace();
}
You can use handler
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do something
}
}, 2000 );//time in milisecond
try {
//set time in mili
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
edited as your code
kileri.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("F");
try {
//set time in mili
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
sendData("S");
}
});
Use handler like this:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// do something after 2s = 2000 miliseconds
}
}, 2000); //Time in milisecond
You can do like this
kileri = (Button) findViewById(R.id.kileri);
final EditText value1 = (EditText) findViewById(R.id.textkont);
assert value1 != null;
value1.setText("0");
final int a = Integer.parseInt(value1.getText().toString());
final int b = a/22;
final int c = b/2; // It will take a int from Edittext and do this operation on that.
btAdapter = BluetoothAdapter.getDefaultAdapter();
checkBTState();
kileri.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("F");
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
sendData("S");
}
}, c);
}
});
just use runOnUiThread on button click and post Handler after time delay..
Button button = new Button(this);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendData("F"); // send
delay(2000);
}
});
UPDATE
delay()..
public void delay(final int c){
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(c);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
sendData("S"); //send
}
}, c);
}
It's not recommended to use Thread.Sleep because it stops execution of main thread if it is called in main thread execution.So,if we want to set delay we can use CountDownTimer.
In below snippet,we gave 2 seconds delay.So,after 2s onFinish() callback comes and we can have our operation there.
new CountDownTimer(2000, 1000) {
public void onFinish() {
}
public void onTick(long millisUntilFinished) {
}.start();
}

How to properly interrupt a thread in android

In my application I have a button and when it gets clicked I start a new thread and change the text of button. If I press the button again it will start changing its text faster.
I would like to interrupt the thread when the button is pressed in the second time. What's the correct way to do it?
public class TestActivity extends Activity {
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
In this case, just keep a reference to your thread and use Thread.interrupt():
private Thread runThread() {
return new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Then:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (myThread != null) myThread.interrupt();
myThread = runThread();
myThread.start();
}
});
Read this post for more info and options:
How to properly stop the Thread in Java?
In my opinion, the best way would be using a variable to control this.
Something like:
while(i++ < 1000 && keepRunning)
I see that as a good solution because it cant cause unexpected behavior, as you are sure the exactly moment your thread would exit.
extra--
As a suggestion, I also would recommend you to set your thread non-Damon (setDaemon(false)) because it makes layout changes
Also it is a good practice to give thread a name (setName()) to make it easy on debugging.
Right now you start a new Thread each time you press the button.
Something like this should work.
public class TestActivity extends Activity {
Button btn;
int i = 0;
Thread countThread = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
countThread = new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread() {
if(countThread != null) {
if(countThread.isAlive()) {
countThread.stop();
} else {
countThread.start();
}
}
}
I only had a text editor so I can't guarantee if this solves your problem.
You can use thread.interrupt() to interrupt the thread.
Try this, Just take another variable j and it will handle your code:-
public class TestActivity extends Activity {
Button btn;
int i = 0,j=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
j=1;
runThread();
}
});
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(j==1){
btn.setText("#" + i);
j=0;
}
else
Thread.interrupted();
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
You can use normal Thread in Android (and call interrupt() for your use case) but frameworks provides other better options by providing helper classes around Threads. You can refer to official documentation page for other options.
HandlerThread is preferred option. You can call quitSafely() or quit() for your use case if you go for HandlerThread
Related post:
Why use HandlerThread in Android

After onCreate Android

I'm new to android and I want to do a simple example where I click on a start button and another Activity is open, there a simple number starting in one and counting upwards, but I'm facing a problem, after I initialize some variables on onCreate method (In the second activity), where should I actually start the while statement to count and modify the text view?.
I wrote this class:
public class Counter extends Thread{
private TextView tv;
private int i;
public Counter( TextView tv ){
this.tv = tv;
}
#Override
public void run() {
while( true ){
tv.setText(i);
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i++;
}
}
And started the thread over here:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
counter = new Counter( (TextView) findViewById(R.id.textView2) );
counter.start( );
}
#SuppressLint("UseValueOf")
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
// change your text here
if (condition) {
i++;
txt_TimeRecord.setText("" + i);
} else {
i = 0;
}
handler.postDelayed(this, 1 * 1000L);
}
});
[Formatted the code properly]
//In first activity
//set onclick method to that button.
public void onclick(view v)
{
Intent intent = new Intent(this, secondactivity.class);
startActivity(intent);
}
// in second activity in
// initi i value.
while(i<10)
{
i++ ;
// sleep statement
//print that i in textview
}
I've found what I need from a similar post, the handler was needed since only the UI Thread can update the user interface.
private void countNumbers() {
final TextView numbers = (TextView) findViewById(R.id.textView2);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
int i = 0;
while (i++ < 500) {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
e.printStackTrace();
}
final int j = i;
handler.post(new Runnable(){
public void run() {
numbers.setText(Integer.toString(j));
}
});
}
}
};
new Thread(runnable).start();
}
The method countNumbers() is called in onCreate().

How can I stop a Timer?

I have a simple question, how can I stop timer?
Button bCancel = (Button)findViewById(R.id.bt1);
bCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
startActivity(new Intent("com.jom.testcdt2.CANCELCLASS"));
}
});
final Thread logoTimer = new Thread(){
public void run(){
try {
int logoTimer = 0;
while (logoTimer < 10000) {
sleep(100);
logoTimer = logoTimer + 100;
}
startActivity(new Intent("com.jom.testcdt2.CLEARSCREEN"));
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally{
finish();
}
}
};
logoTimer.start();
}
When I press button bCancel, it starts a new activity, but timer is still running and after 10 seconds it starts CLEARSCREEN. On click I want timer to stop. How can I do that?
I would recommend using a CountDownTimer:
final CountDownTimer myTimer = new CountDownTimer(10000, 5000) {
#Override
public void onFinish() {
//DO SOMETHING AFTER 10 000 ms
}
#Override
public void onTick(long millisUntilFinished) {
//DO SOMETHING EVERY 5 000 ms until stopped
}
}
myTimer.start() //Starts it
myTimer.cancel() //Stops it
And instead of writing
(new Intent("com.jom.testcdt2.CANCELCLASS")
you should use
(new Intent(YOURCLASS.this, CancelClass.class)
Could you try to have a boolean value that you check in the while loop, and set it to true when you press the cancel button?
boolean pressedCancel = false;
....
while (logoTimer < 10000 && !pressedCancel) {
....

Categories