So, I am trying to access my variable from timer task, however I can't seem to make it work. I read about global variables but wasn't quite sure on how to use it. I am new to Java so any suggestion would be extremely helpful, thank you!
public boolean verifyAnswer(String userAnswer) {
String correctAnswer = this.questions.get(currentQuestionIndex).correctAnswerText;
if(userAnswer.equals(correctAnswer)) {
timer.pauseTimer();
Timer t = new Timer();
TimerTask tt = new TimerTask() {
//This is the variable I want to use
int score = 0;
#Override
public void run() {
System.out.println(++score);
if (score == 30) {
t.cancel();
}
};
};
t.scheduleAtFixedRate(tt, 0, 1000);
TimerPanel timer2 = new TimerPanel();
long total = 0;
//Here is where I try to use it
long equation = TimerTask.score / 30000;
The simplest workaround would be to use a single-element array or holder object to store the score as anonymous inner classes cannot modify the value of outer variables.
int[] score = {0};
TimerTask tt = new TimerTask() {
#Override
public void run() {
System.out.println(++score[0]);
if (score[0] == 30) {
t.cancel();
}
};
};
//...
long equation = score[0] / 30000;
a global variable might indeed help. It is just a variable declared outside the methods but inside the class. Then it is visible in the entire class - and also from outside if you make it public.
of you are in a multithreading environment, please access it in a synchronized way, like so
public class Test {
public volatile int global_variable = 42;
public synchronized int getGlobal_variable() {
return global_variable;
}
public synchronized void setGlobal_variable(int global_variable) {
this.global_variable = global_variable;
}
public void update() {
setGlobal_variable(getGlobal_variable() + 150);
}
public Test() {
try {
while (true) {
System.out.println(getGlobal_variable());
update();
Thread.sleep(1000);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
new Test();
}
}
note that I have added the volatile just to be on the safe side.
it depends upon your application whether you really need that.
if you are not concerned with multithreading, just move the declaration of score outside your method and you will be fine :-)
Related
Please fix it incompatible type require int found boolean on timer.schedule run() curInterval,What's wrong with my code?
public class HeartbeatPacket implements HeartbeatStop {
private final String TAG = getClass().getSimpleName();
private int curInterval = 0;
private HeartbeatStop heartbeatStop = null;
private final int setInterval;
private Timer timer;
public HeartbeatPacket(HeartbeatStop heartbeatStop, int setInterval) {
this.heartbeatStop = heartbeatStop;
this.curInterval = setInterval;
this.setInterval = this.curInterval;
}
public void callStopFun() {
if (this.heartbeatStop != null) {
this.heartbeatStop.callStopFun();
}
}
public void recover() {
synchronized (this) {
this.curInterval = this.setInterval;
}
}
private void run() {
if (this.timer == null) {
Log.e(this.TAG, "null == timer");
} else {
this.timer.schedule(new TimerTask() {
public void run() {
synchronized (this) {
//this is the problem section
if (HeartbeatPacket.this.curInterval = HeartbeatPacket.this.curInterval - 1 < 0) {
HeartbeatPacket.this.callStopFun();
HeartbeatPacket.this.recover();
HeartbeatPacket.this.stop();
}
}
}
}, 0, 1000);
}
}
public void start() {
recover();
this.timer = new Timer();
run();
}
public void stop() {
this.timer.cancel();
this.timer = null;
}``
}
I think the Java compiler should have complained about the
if(HeartbeatPacket.this.curInterval = HeartbeatPacket.this.curInterval - 1 < 0) . Did you happen to see some compilation error message?
The operator order of precedence is not what you think it is, especially with = and <. The comparison is done first, resulting in a boolean type, which is then assigned to an int field -- which is illegal.
In general, it's not a good idea to combine assignment and/or modification of a variable within the if conditions. It's hard to read, and error-prone (as seen here). Change your value before the if, and then do compare to the plain value.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (counter <= 200) {
doThing();
counter++;
handler.postDelayed(this, 50);
}
}
}, 0);
In the above code I have a Handler running a Runnable. My issue is that since the counter object is inside a Runnable it will need to be declared final.
What is the best way to handle this incrementing value?
Currently I am simply using a counter object but I feel it should be easier:
class Counter {
int count;
Counter() {
count = 0;
}
public void addOne() {
count++;
}
}
There are already classes that you could use instead, like AtomicInteger, or similar, but slightly different LongAdder.
You instantiate an object of that class, and then you can simply invoke various methods that will change the internal value of that object.
These classes also provide the required thread safety. Without that property, it is rather unlikely that your counter will count up correctly!
Rather than using postDelayed(), you could use sendMessageDelayed(). You could send a Message that indicates that you want to run that runnable, and then use the arg1 field to store the current count.
private static final int WHAT_DO_WORK = 1;
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == WHAT_DO_WORK) {
doWork(msg.arg1);
}
}
};
private void doWork(int counter) {
if (counter <= 200) {
doThing();
int arg1 = count + 1;
Message message = Message.obtain(handler, WHAT_DO_WORK, arg1, 0);
handler.sendMessageDelayed(message, 50);
}
}
I have two classes that I'm trying to manipulate one variable with, as an example
public class A {
public static void main(String[] args) {
while(game_over[0] == false) {
System.out.println("in the while-loop");
}
System.out.println("out of the while-loop");
}
static boolean[] game_over = {false};
}
and
public class B {
public boolean[] game_over;
public printBoard(boolean[] game_over) {
this.game_over = game_over;
}
public void run() {
for (int i = 0; i < 10; i++) {
// do something
}
game_over[0] = true;
System.out.println("GAME OVER");
}
}
The code snippets provided are not meant to be actual workable code, I'm more concerned with the concept. In my program, class A creates a thread that utilizes class B, and I want class B to affect the variable 'game_over' such that the while-loop in class A will be affected by the change... any idea how I can successfully update the variable? Thanks.
Don't use an array for this, that makes it harder to ensure a data-race free application.
Since you want to be able to pass around the game_over flag as an independent object, the easiest way to achieve a correct multi-threaded application is to use the AtomicBoolean class.
import java.util.concurrent.atomic.AtomicBoolean;
class B {
private AtomicBoolean game_over;
public B(AtomicBoolean game_over) {
this.game_over = game_over;
}
public void run() {
// do stuff
game_over.set(true);
}
}
and in your class A:
public class A {
static AtomicBoolean game_over = new AtomicBoolean();
public static void main(String[] args) {
B b = new B();
Thread t = new Thread(b);
t.start();
while (!game_over.get()) {
System.out.println("in the while-loop");
}
System.out.println("out of the while-loop");
}
}
I don't know if the following thing is possible. I would like a Runnable's run() method to contain the Runnable itself, i.e.
reconnects = 3;
Runnable executeAfter = () -> {
if ( --reconnects < 0 ) {
println("%nStop using port %d.", this.port);
//...
} else { // try to reconnect
println("%nReconnecting...");
cmdRun = new CmdRun(command, executeAfter);
(new Thread(cmdRun)).start();
//...
}
};
Is something like this even possible? If so, how? (CmdRun's constructor is CmdRun(String command, Runnable executeAfter))
Is lambda a must here? If not, switching to older equivalent syntax should be simple:
An example:
public class TestLambda {
static int count = 0;
public static void main(String[] args) {
// lambda not going to work
//Runnable foo = () -> { if (count < 5) { call(foo); } };
// nor
//Runnable foo = () -> { if (count < 5) { call(this); } };
// using old way of anonymous inner class will work
Runnable foo = new Runnable() {
#Override public void run() {
if (count < 5) {
call(this);
}
}
};
foo.run();
}
public static void call(Runnable action) {
count++;
System.out.println("in call " + count);
action.run();
}
}
The easiest way is probably to put the content of your lambda in a method and use a method reference to define your Runnable.
The Runnable's run() can not contain a self reference as its illegal.
Im not exactly sure what you are trying to achieve but something like this should work :
class CmdRun implements Runnable {
final Object command;
final Runnable runnable;
final Runnable executeAfter = () -> {
if ( --reconnects < 0 ) {
System.out.println("%nStop using port %d." + port);
//...
} else { // try to reconnect
System.out.println("%nReconnecting...");
CmdRun cmdRun = new CmdRun(command);
(new Thread(cmdRun)).start();
//...
}
};
public CmdRun(Object command) {
this.command = command;
this.runnable = executeAfter;
}
#Override
public void run() {
runnable.run();
}
}
Short answer: No.
Long answer:
Your code will give you a syntax error. Why? The executeAfter used inside the lambda is not initialized; it is only initialized after the full body of the lambda definition.
For example, consider the below example.
int i;
sum(i, 5); // Syntax error!! Variable i is not initialized...
Your case is similar. Inside the lambda, executeAfter is not initialized. As stated above, it is only initialized after the full body of the lambda's definition.
One additional thing to node is that the variable reconnects must be a final in order to be used inside the lambda. If it is a final variable, then you cannot use the -- operator on it inside your if condition.
Actually if you don't mind to introduce a new interface (or if you require such functionality more often), you could use the following:
#FunctionalInterface
interface RecursiveRunnable extends Runnable {
default void run() {
run(this);
}
public void run(RecursiveRunnable runnable);
}
This will now allow you to recursively call the runnable, e.g.:
int maxTries = 3;
AtomicInteger counter = new AtomicInteger();
RecursiveRunnable foo = runnable -> {
if (counter.getAndIncrement() < maxTries) {
println("Reconnecting... %n");
runnable.run(); // same as: runnable.run(runnable)
} else {
println("Stop using port %d%n", port);
}
};
I'm new to Java, and I have a problem. I've copied some code off a tutorial for Android, and now I want to pass an integer variable into the method run(), so I can increment it for each loop and then catch it outside the background Thread. How would I do that?
int gg= 0;
Thread background = new Thread(new Runnable() {
public void run() {
try {
while (pBarDialog.getProgress() <= 100) {
Thread.sleep(100);
gg++; // the increment here
progressHandler.sendMessage(progressHandler
.obtainMessage());
}
if (pBarDialog.getProgress() == 100) {
pBarDialog.dismiss();
}
} catch (java.lang.InterruptedException e) {
// if something fails do something smart
}
}
});
//catch gg here
You can't specify argument to the run() method. You may declare int variable as field and use it in inner classes.
public class TestActivity extends Activity
{
private volatile int no;
.....
}
EDIT: (Suggestion from #alf) You can use volatile modifier with field so changed value can be seen immediately by all other threads.
Have your own class and pass the counter using its constructor, I haven't tried that, but I would start with something like that:
class MyThread implements Runnable {
private volatile int counter;
public MyThread( int counter ) {
this.counter = counter;
}
public void run() {
...
}
public getCounter() {
return counter;
}
}
MyThread mt = new MyThread( 10 );
Thread t = new Thread( mt );
t.start();
// after some time
t.getCounter();
private volatile int gg;
public void myMethod() {
Thread background = new Thread(new Runnable() {
#Override
public void run() {
try {
while (pBarDialog.getProgress() <= 100) {
Thread.sleep(100);
gg++; // the increment here
progressHandler.sendMessage(progressHandler.obtainMessage());
}
if (pBarDialog.getProgress() == 100) {
pBarDialog.dismiss();
}
} catch (java.lang.InterruptedException e) {
// if something fails do something smart
}
}
});
System.out.println(gg);
}
If I were you, I'd be looking into AtomicInteger, namely the incrementAndGet() method.
Making gg a field will indeed give the thread access to gg, and volatile will make the changes visible, but since your intentions are not clear, I cannot be sure that you don't have other threads incrementing the same value: you don't have atomicity, so as soon as you have more than one thread doing gg++, you're likely to get wrong results.