Checking integer against array index not working - java

I'm making an android app where you tap a button to stop a looping counter when it is showing a particular number. I have an array (aNums) holding some int values and want the counter to stop when it is clicked when showing the first number in the array (in this case "2"). For some reason however it decides to stop on "1" when clicked. I'm not sure if my code is just wrong or if there's a timing issue and it's stopping right when it's about to change to the number "2". Here is my code so far:
public class MainActivity extends Activity {
public int a = 0;
private Handler handler = new Handler();
TextView textView2;
Button Stop;
public Runnable myRunnable = new Runnable() {
#Override
public void run() {
updateText();
a = ++a % 10;
if (a < 10) {
handler.postDelayed(this, 1000);
}
}
};
public int aNums[] = { 2, 4, 6, 8, 10, 12 };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView2 = (TextView) findViewById(R.id.textView2);
loop();
Stop = (Button)findViewById(R.id.Stop);
Stop.setOnClickListener(handler2);
}
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
public void loop() {
handler.post(myRunnable);
}
public void updateText() {
textView2.setText("" + a);
}
public void Stop() {
super.onStop();
handler.removeCallbacks(myRunnable);
}
}
Does anyone know what the problem is?
Thanks

You forgot two closing brackets here:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i <= aNums.length; i++) {
if (a == aNums[0]) {
Stop();
} //I added this
}
}
}//and this
but I think there is no need for a for loop here: you want to stop the thread when you click at the moment a equals the number in your array at index 0, right?
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
Also, this check is not necessary because a will never be 10 or more:
if (a < 10) {
handler.postDelayed(this, 1000);
}
The last thing: when you quit the thread, the text is not updated. Try adding the updateText() after the click:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
updateText();
}
}
}

Related

Why value of only last iteration(999) is printed in the text field ? I want all numbers to be printed before getting replaced by next number

I am new to android studio and want to overcome from this problem.
It gonna help me a lot while creating some future apps like , stopwatch, timer etc etc.
Thanks in advance !!
public class MainActivity extends AppCompatActivity {
private EditText k;
private Button start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
k=findViewById(R.id.kf);
start=findViewById(R.id.startf);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=1;i<1000;i++)
{
k.setText(String.valueOf(i) );
}
}
});
}
}
As #f1sh already mentioned in the comments your for loop is executing at such a speed that all you see is the final value. For such cases in android one of the best solutions is to make use of Handler for posting delayed functions without blocking the UI.
So for showing 1 to 999 you can try something like this:
public class MainActivity extends AppCompatActivity {
private EditText k;
private Button start;
int count;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
k=findViewById(R.id.kf);
start=findViewById(R.id.startf);
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
if (count < 1000) {
k.setText(String.valueOf(count));
count++;
handler.postDelayed(this, 1000);
} else {
handler.removeCallbacks(this);
}
}
};
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count = 1;
handler.postDelayed(runnable, 0);
}
});
}
}
this will keep changing the text in TextView with a 1 second delay, you can change the delay as needed by setting the milliseconds in runnable.
You can even use a countdown timer for this purpose but its more like a workaround and requires you to calculate the correct time etc.
For example displaying 1 to 10 would be something like this:
...
count = 1;
new CountDownTimer(11000, 1000) {
public void onTick(long millisUntilFinished) {
tv.setText(String.valueOf(count));
count++;
}
public void onFinish() {
}
}.start();
here you are displaying the value every 1 second for 11 seconds

Button supposed to click 5 times through an string array, stop 5 secs and then continue(clicking 5 times) CONSISTENTLY, ERROR

My problem is I cant get my button to consistently click 5 times through a string array which is displayed in a TextView ,
whenever the maxclicks(5) and currentnumber get to 5 it stops working , Ive been trying to create if conditions to work around it, well somehow I have to manipulate my currentnumber to NOT be 5 because IF maxclicks == currentnumber my button is enabled.
In the Code below it stops just afte the first time of clicking 5 times.
so here is the Code :
public class MainActivity extends AppCompatActivity {
int currentnumber = 0;
int mod = 5;
TextView display = findViewById(R.id.tx);
Handler handler = new Handler();
int delay = 5000;
int maxclicks = list.length;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
final String[] list = res.getStringArray(R.array.xyz);
final Button next_button = findViewById(R.id.next_btn);
{
((TextView) findViewById(R.id.tx)).setText(list[currentnumber]);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(currentnumber == maxclicks){
currentnumber = 0;
}
if (currentnumber % mod == 0) {
next_button.setEnabled(false);
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
currentnumber++;
}
}, delay);
}
else {
display.setText(list[currentnumber]);
currentnumber++;
}
}
});
}
}
}
welcome to SO :) I did my best to understand on your explanation,so this is my solution for your problem and don't forget you can make your vars global to avoid final and one element array thing:
public class MainActivity extends AppCompatActivity {
private int currentnumber,mod,delay,Curclicks;
private TextView display;
private Handler handler;
private Button next_button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
//Binding
display = findViewById(R.id.tx);
next_button = findViewById(R.id.next_button);
//getResources
Resources res = getResources();
//getting the data ready
String[] list = {"1","2","3","4","5","6","7"};
//assign vars
handler = new Handler();
currentnumber = 0;
Curclicks=0;
mod = 5;
delay = 5000;
//initial view
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(currentnumber == list.length){
currentnumber = 0;
}
if (Curclicks == mod-1) {
next_button.setEnabled(false);
display.setText(list[currentnumber]);
currentnumber++;
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
Curclicks = 0;
}
}, delay);
}
else {
display.setText(list[currentnumber]);
currentnumber++;
}
Curclicks++;
}
});
}
}

How to stop postDelayed after x number of times

I am creating an animation that randomly selects a string that's pulled from an XML string array. It does this in rapid succession to make it look kind of like a slot machine. I got the animation going, but I do not know how to stop it after x times. Here's what I have thus far:
public class MainActivity extends AppCompatActivity {
TextView locationsTextView;
Button generateBtn;
String[] mArray;
int counter; //<-- This is how I would like to keep track of when handler should stop
Handler h = new Handler();
int delay = 50;
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationsTextView = findViewById(R.id.locationsTextView);
generateBtn = findViewById(R.id.generateBtn);
mArray = getResources().getStringArray(R.array.locations_array);
locationsTextView.setText("");
generateBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
h.postDelayed(new Runnable() {
public void run() {
updateTextView();
runnable = this;
h.postDelayed(runnable, delay);
}
}, delay);
}
});
}
private void updateTextView() {
Random random = new Random();
int maxIndex = mArray.length;
int generatedIndex = random.nextInt(maxIndex);
locationsTextView.setText(mArray[generatedIndex]);
}
}
I am thinking that something like this would work:
//pseudo code
//Button is clicked
//initialize counter to 0
counter = 0;
//updateTextView method is called repeatedly
counter ++;
if(counter == 50) {
h.removeCallbacksandMessages(null);
}
I just don't know where I would place that in the code.
If I would've taken a few more minutes before posting, I think I figured it out. See code below:
generateBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counter = 0; //<-- every click, set back to 0
h.postDelayed(new Runnable() {
public void run() {
counter++; //<-- increment with every method call
updateTextView();
runnable = this;
h.postDelayed(runnable, delay);
if(counter == 50) { //<-- stop after 50
h.removeCallbacksAndMessages(null);
}
}
}, delay);
}
});
}

Android using two countdowntimers

In my app, i'm using two different CountDownTimers that have same values. I have two buttons to control them but when i press the button twice, it starting from the beginning. I want to keep its last value.
Here is my code:
t1 = new CountDownTimer(white, 1000) {
#Override
public void onTick(long l) {
btnWhite.setText("seconds remaining: " + l / 1000);
white = l;
}
#Override
public void onFinish() {
}
};
t2 = new CountDownTimer(black, 1000) {
#Override
public void onTick(long l) {
btnBlack.setText("seconds remaining: " + l / 1000);
black = l;
}
#Override
public void onFinish() {
}
};
btnBlack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
t1.start();
t2.cancel();
}
});
btnWhite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
t2.start();
t1.cancel();
}
});
I have tested this and it works!
I have two TextViews and two Buttons. The black button is next to the black text view and the white button is next to the white text view.
First I declare the important constants.
//contains the elapsed time for each of the timers
long blackElapsed=0,whiteElapsed=0;
//contains the total time with which we start new timers
long totalWhite = 30000;
long totalBlack = 30000;
Next I initialise the CountDownTimers. Whatever you put in here doesn't matter. I only have this so that the timers will be initialised with some value.
The reason is that they have to be initialised in order to be able to .cancel() them later in the OnClickListeners.
black = new CountDownTimer(totalWhite, 1000){
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
}
};
white = new CountDownTimer(totalBlack, 1000){
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
}
};
Finally the OnClickListeners for the buttons. (W is white textView and B is black textView and b is black button and w is white button)
w.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
black.cancel();
//using the elapsed time to start a new timer
totalBlack = totalBlack - blackElapsed;
//this preserves milliseconds by ticking every millisecond
white = new CountDownTimer(totalBlack, 1){
#Override
public void onTick(long l) {
B.setText(l+"");
blackElapsed=totalBlack-l; //updating the elapsed time
}
#Override
public void onFinish() {
}
}.start();
}
});
//we do a similar thing with the other player's button
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
white.cancel();
totalWhite = totalWhite - whiteElapsed;
black = new CountDownTimer(totalWhite, 1){
#Override
public void onTick(long l) {
W.setText(l+"");
whiteElapsed=totalWhite-l;
}
#Override
public void onFinish() {
}
}.start();
}
});
I have checked your code.
It is obvious because your timers initialised with default values. when you start again it won't take new values of white/black.
To achieve what you want you have to initialise timer with new values before starting it.
I have done some correction in your code. you can check that out.
Make Two methods
public void timerStart1(long timeLengthMilli) {
t1 = new CountDownTimer(timeLengthMilli, 1000) {
#Override
public void onTick(long l) {
isRunning1 = true;
tv1.setText("seconds remaining: " + l / 1000);
white = l;
}
#Override
public void onFinish() {
isRunning1 = false;
}
}.start();
}
public void timerStart2(long timeLengthMilli) {
t2 = new CountDownTimer(timeLengthMilli, 1000) {
#Override
public void onTick(long l) {
isRunning2 = true;
tv2.setText("seconds remaining: " + l / 1000);
black = l;
}
#Override
public void onFinish() {
isRunning2 = false;
}
}.start();
}
and set setOnClickListener like this
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isRunning1) {
isRunning2 = false;
timerStart1(white);
if (t2 != null)
t2.cancel();
}
}
});
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isRunning2) {
isRunning1 = false;
timerStart2(black);
if (t1 != null)
t1.cancel();
}
}
});
UPDATE :
Please check updated code and take these extra variables
boolean isRunning1 = false, isRunning2 = false;
Hope this will help you.
Happy Coding.

How to stop a thread in Java Android?

This is the code of my testing app:
public class MainActivity extends Activity
{
private TextView text;
private Button start;
private Button stop;
private TestThread Points;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (TextView) findViewById(R.id.mainTextView1);
start = (Button) findViewById(R.id.mainButton1);
stop = (Button) findViewById(R.id.mainButton2);
Points = new TestThread();
start.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View p1)
{
if (! Points.isAlive())
{
Points.start();
}
}
});
stop.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View p1)
{
if (Points.isAlive())
{
Points.stop();
}
}
});
}
public class TestThread extends Thread
{
private String points;
#Override
public void run()
{
for (int a = 0; a < 3; a++)
{
try
{
if (a == 0) points = ".";
else if (a == 1) points = "..";
else if (a == 2) {
points = "...";
a = -1;
}
runOnUiThread(new Runnable()
{
#Override
public void run()
{
text.setText(points);
}
});
Thread.sleep(350);
} catch (InterruptedException e) {}
}
}
}
}
When I click on Start button the thread starts successfully but when I click on Stop button the app crashes...
How can i stop the thread successfully without force closing?
Thanks a lot
Thread.stop() function is deprecated and should not be used to stop a thread.
this is according to the java docs.
a good way to stop a thread is make it exit its run method.
a simple way to achive this is by adding a boolean member to your thread class:
public class TestThread extends Thread
{
private String points;
private boolean keepRunning = true;
public cancel(){
keepRunning = false;
}
#Override
public void run()
{
for (int a = 0; a < 3; a++)
{
if(!keepRunning) break;
try
{
if (a == 0) points = ".";
else if (a == 1) points = "..";
else if (a == 2) {
points = "...";
a = -1;
}
runOnUiThread(new Runnable()
{
#Override
public void run()
{
text.setText(points);
}
});
Thread.sleep(350);
} catch (InterruptedException e) {}
}
}
}
call the TestThread.cancel() function in your stop button onClick method.
Other than adding a Boolean to stop it I believe you could catch InterruptException and just call Thread.interrupt(); which would exit the loop this ending the thread

Categories

Resources