Asycntask's onprogressupdate is always being called, :
#Override
protected void onProgressUpdate(Integer... values) {
pbSubStatus.incrementProgressBy(values[1]);
rawNum = values[0];
...
}
And on outer class:
private double getCurrentTime() {
return currentTime;
}
private void doSomethingOnThread() {
LinearLayout layout = (LinearLayout) findViewById(R.id.main);
sMeter = new Meter(context);
layout.addView(sMeter);
final Handler mHandler = new Handler();
new Thread() {
#Override
public void run() {
while (running) {
previousTime = getCurrentTime();
previousNum = getRawNum();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentTime=getCurrentTime();
currentNum = getRawNum();
mHandler.post(mUpdateResults);
}
}
}.start();
}
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
private void updateResultsInUi() {
if(previousNum>currentNum){
return;//TODO
}else{
int temp=currentNum-previousNum;//Problem here, both num are same.
double timeTemp=currentTime-previousTime;
someField= (float)( temp/timeTemp);
}
sMeter.setTarget(someField);//this should be last line to be executed in this snippt
}
So the problem is previousNum and currentNum are always returning the same number. I want the thread to wait 1.5 sec to get a new (getRawNum()) from the onProgressupdate. But I don't understand they they are returning the same number. Thanks for any advice.
I don't think this section is doing what you want:
while (running) {
previousTime = getCurrentTime();
previousNum = getRawNum();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentTime=getCurrentTime();
currentNum = getRawNum();
mHandler.post(mUpdateResults);
}
For instance, let's say this starts executing at time=0. At the end of the first iteration you will have:
previousTime = 0
currentTime = 1500
...however, the loop will immediately start its second iteration, and then you will have:
previousTime = 1500
currentTime = 1500
...then it will sleep for another 1500 milliseconds and set currentTime to 3000, and then immediately start the next iteration, setting previousTime to 3000 as well.
So the problem is that for the vast majority of the time, your code is leaving currentTime and previousTime set to the same value. The only time they have different values is for the extremely small span of time in between when one iteration ends and the next iteration begins.
A quick way to work around this problem is as follows:
currentTime = getCurrentTime();
currentNum = getRawNum();
while (running) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
previousTime = curentTime;
previousNum = currentNum;
currentTime=getCurrentTime();
currentNum = getRawNum();
mHandler.post(mUpdateResults);
}
A better approach might be to refactor your code to use something like a circular buffer to keep track of the last n samples and sample timestamps. Then you can simply query for a new sample at regular intervals, and when updating the UI you just compare the most recent thing in the buffer against the one that came immediately before it.
And as for fields in your UI not updating, make sure that the code you have that tries to update them is running on the main thread.
Related
why the result is always 101?
I think the result should be random since is shareVar not thread safe
public class ThreadQuestion
{
public static int shareVar = 1;
public static void main(String[] args) throws InterruptedException
{
ExecutorService threadPool = Executors.newFixedThreadPool(20);
for(int i = 0; i < 100; i++)
{
threadPool.execute(new Runnable()
{
#Override
public void run()
{
shareVar++;
}
});
}
//wait for other thread finish
Thread.sleep(5000);
System.out.println("shareVar is " + shareVar );
threadPool.shutdown();
}
}
Your concurrent tasks run practically sequential because CPU extremely fast so your task(increment) will run really quick. Your loop execute a bit slower so when you add new task old task will be already executed. Moreover concurrency it's always about theory of chances and 100 it's a small value for getting glitches for this short task.
You should expand loop to bigger value for example to 10000 or even 10000 or just put a tiny delay in your code like this:
for (int i = 0; i < 100; i++) {
threadPool.execute(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10);
shareVar++;
} catch (InterruptedException ex) {
Logger.getLogger(ThreadQuestion.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
in this case you'll really try to run several threads in the same time and result will change from 101 to about a hundred.
I'm making a Simon game, while doing it, I created an method that called "Computer" that is activated when the game is starting and after that, every time after the player successes to repeat the sequence.
Here is the code:
private void Computer(){
rounds.setText("Round " + index);
new CountDownTimer(500, 500) {
public void onTick(long millisUntilFinished) {
}
public void onFinish()
{
ResetArray(Player);
//Pushing buttons
Red.setClickable(false);
Blue.setClickable(false);
Green.setClickable(false);
Yellow.setClickable(false);
for (int i = 0; i < index; i++)
{
final Handler handler = new Handler();
final int temp=Game[i];
if (temp == 0)
{
Red.setImageResource(R.drawable.red1);
handler.postDelayed(new Runnable() {
#Override
public void run()
{
StartSound(red);
Red.setImageResource(R.drawable.red);
}
}, 100);
}
if (temp == 1)
{
Green.setImageResource(R.drawable.green1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(green);
Green.setImageResource(R.drawable.green);
}
}, 100);
}
if (temp == 2)
{
Blue.setImageResource(R.drawable.blue1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(blue);
Blue.setImageResource(R.drawable.blue);
}
}, 100);
}
if (temp == 3)
{
Yellow.setImageResource(R.drawable.yellow1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(yellow);
Yellow.setImageResource(R.drawable.yellow);
}
}, 100);
}
}
Red.setClickable(true);
Blue.setClickable(true);
Green.setClickable(true);
Yellow.setClickable(true);
}
}.start();
}
So basically, what iv'e done here is a short delay, of 500 milliseconds, and then it is starting with the self "pushing". This is for create some space between the beginning of the game/starting a new round.
Index- round number.
Game- an array that iv'e created, where there is 50 random numbers which presents the sequence, every round i'm adding one for the index.
Red, Green, Blue, Yellow - References for ImageButtons.
The handler delay is to give some time between the button pressing (which presented by switching the image resource to a same color but brighter, that gives the effect of pressing a button) and un-press it, without it, the changing will be so fast so the player will not be able to see any graphical change.
Basically I need a way to stop the program for a while between each pushing. I need a delayer that will delay the loop every time at it's beginning. The countdowntimer and the Handler are not suitable because the program keeps "running" after the declaring and setting those, the only effect is that the buttons are pushed together but in a delay, which is not what I need.
The result now is that the buttons are seems pushed together and I need to separate their pushing in some way.
Iv'e tried everything, and I could not find nothing.
Thanks,
Ziv.
Using a Handler and postDelayed(...) IS exactly what you need but you're a approaching it wrong.
Basically what you are doing is running through your for loop almost instantly and at each loop you're calling postDelayed(...) with a delay of 100ms.
I'll explain further - suppose index is 4 and it only takes 1ms to go through each run of the for loop. When the 4 runs of the loop are complete you'll have 4 postDelayed events with times of 100ms, 99ms, 98ms & 96ms - - to all intents and purposes, when they trigger they all appear to trigger at once.
One easy way around this with your code is to increase each delay based on the loop count...
int delayTime;
for (int i = 0; i < index; i++)
{
delaytime = (i + 1) * 100;
final Handler handler = new Handler();
final int temp=Game[i];
if (temp == 0)
{
Red.setImageResource(R.drawable.red1);
handler.postDelayed(new Runnable() {
#Override
public void run()
{
StartSound(red);
Red.setImageResource(R.drawable.red);
}
}, delayTime); // NOTE USING delayTime AS THE DELAY
}
//
// REPEAT THE ABOVE CODE FOR BLUE, GREEN & YELLOW HANDLER DELAYS
}
In other words when i=0, delayTime will be 100ms, when i=1, delayTime is 200ms etc etc
probably you want to sleep the thread for 500 milliseconds, then you can do this to slept your thread.
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I am wondering the best way to keep a timer going in the background while a game is played.
I am programming a version of the HiLo game (in Java), which gives a user a certain amount of time to determine a number. If a guess is not correct, the game will tell the user whether the name is too high or too low.
I'm keeping track of time using System.currentTimeMillis() and seeing how much time has elapsed. This seems to work well, and so far I have been checking to see how much time has elapsed each time a new number is entered. For example, currently the app output looks like this:
Welcome to HiLo!
You have 10 seconds to guess a number I'm thinking of between 1 and 100.
> 67
Too high.
> 29
Too low.
Half of your time is gone! Only 5 seconds remains!
> 37
Too high.
> 33
Oops! Time is up - try again.
As you can see, currently, it can only check when I enter a new number how much time is passed.
I have tried creating a thread to start with a timer, however, when I start it, it keeps counting until the time is exhausted, without going on to the thread.run(int guess) which will be run when there is a new guess. I want to be able to still make guesses while the counter runs. Here is my attempt at a new implementation for thread.start():
public void start(int time_sent) throws InterruptedException {
time = time_sent;
startTime = (System.currentTimeMillis() / 1000);
while (1==1) {
long elapsed = ((System.currentTimeMillis() / 1000) - (startTime));
if (elapsed >= (time)) {
System.out.println("Oops! Time is up - try again.");
System.exit(0);
}
else if (elapsed >= (time/2) && !halfWarning) {
System.out.println("Half of your time is gone! Only " + (time/2) + " seconds remains!");
halfWarning = true;
}
}
}
How can I continue running this counter in the background?
This is one more approach:
public void game() {
Scanner scanner = new Scanner(System.in);
int time = 10; // sec
message("You have " + time + " seconds to guess...");
new Thread(new Background(System.currentTimeMillis() / 1000, time)).start();
while (true) {
String s = scanner.next();
if (s.equals("55")) {
message("You win");
System.exit(0);
} else {
message("try again...");
}
}
}
private void message(String str) {
System.out.println(str);
System.out.print("> "); // monit
}
You start 1 thread with behavior implemented in Background class. Next you enter while loop to capture user inputs. The Background thread works in background...
private class Background implements Runnable {
private long startTime;
private long time;
private boolean halfWarning;
private Background(long startTime, long time) {
this.startTime = startTime;
this.time = time;
}
#Override
public void run() {
while (true) {
long now = System.currentTimeMillis() / 1000;
long elapsed = now - startTime;
if (elapsed >= (time / 2) && !halfWarning) {
message("\n Half of your time is gone! Only " + (time / 2) + " seconds remains!");
halfWarning = true;
}
if (elapsed >= time) {
message("\n Oops! Time is up - try again.");
System.exit(0);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//ignore
}
}
}
}
Use a ScheduledExecutorService to execute concurrent actions in the future:
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> half = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Half of your time is gone!");
}
}, time / 2, TimeUnit.SECONDS);
ScheduledFuture<?> full = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Oops! Time is up - try again.");
// System.exit(0) ?
}
}, time, TimeUnit.SECONDS);
// check
if (input == toGuess) {
half.cancel();
full.cancel();
}
You could have a Timer thread that prints out these messages and shuts down the listening program.
It might inspire you :
public static class Game extends TimerTask {
private long start;
private long end;
public Game(long end) {
super();
this.start = System.currentTimeMillis();
this.end = end;
}
#Override
public void run() {
while (System.currentTimeMillis() - start < end)
System.out.println(System.currentTimeMillis());
}
}
public static void main(String[] args) {
TimerTask task = new Game(10000);
Timer timer = new Timer();
timer.schedule(task,0);
}
I'm creating a video game and I've got a for loop that recovers your health
public void recoverHealth() {
if (curHealth < finalHealth) {
for (double i = 0; i < finalHealth; i = i + 0.1) {
curHealth = curHealth + 0.1;
System.out.println("health: " + curHealth);
}
}
}
But the problem is that java goes through this so fast it goes from 0-20 before the game even starts. How can I possibly slow down the recoverHealth() method without slowing down the entire game such as Thread.sleep doesn't work..
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
Any ideas?
Put recoverHealth into a separate thread, and use Thread.sleep() as you describe.
Add this to your game program, where curHealth is accessible.
timer = new Timer();
timer.schedule(new TimerTask (){
public void run() {
curHealth = curHealth + 0.1;
}
}, 1000);
#Override
public void run() {
super.run();
final float timePerFrame = 1000 / Options.MAX_FPS;
float timeDiff;
while(!isInterrupted() && isRunning) {
timeDiff = System.currentTimeMillis();
mController.refresh();
timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());
try {
Thread.sleep(Math.max(Math.round(timeDiff), 0));
} catch(InterruptedException e) {
// do nothing
e.printStackTrace();
}
}
Log.e("GameThread", "Thread dead.");
}
This is what my thread is basically doing.
Options.MAX_FPS = 30;
To limit the frames per second, to have some sort of sleeping time between each refresh. The refresh method looks like this:
public synchronized void refresh() {
int mRotation = Math.round((360 + ((-1)*mAccelerometer[0] * 4.5f)) % 360);
mObject.setRotation(mRotation);
// get canvas from surfaceview
if(mSurfaceHolder != null) {
// do all calculations.
if(Looper.myLooper() == Looper.getMainLooper()) {
log("on main thread!");
} else {
log("Not on main thread");
}
Canvas mCanvas = mSurfaceHolder.lockCanvas();
if (mCanvas != null) {
// shift x offset
mScreenWidth = mCanvas.getWidth();
mScreenHeight = mCanvas.getHeight();
// draw black background, clear everything.
mCanvas.drawRect(new Rect(0,0,mScreenWidth, mScreenHeight), mBlackPaint);
// shift & draw all viewobjects if still visible
for(ViewObject view: mViewObjectList.toArray(new ViewObject[mViewObjectList.size()])) {
view.shiftX(-1 * Options.Gameplay.Environment.MOVING_SPEED);
if(view.getX() + view.getWidth() < 0) {
mViewObjectList.remove(view);
}
if(view.getCurrentBitmap() != null)
mCanvas.drawBitmap(view.getCurrentBitmap(), new Rect(0,0,view.getCurrentBitmap().getWidth(), view.getCurrentBitmap().getHeight()), new Rect(view.getX(), view.getY(), view.getX()+ view.getWidth(), view.getY()+view.getHeight()), new Paint());
view.nextFrame();
}
// draw object
final Bitmap sBitmap = mObject.getCurrentBitmap();
mObject.nextFrame();
if(sBitmap != null) {
mCanvas.drawBitmap(sBitmap, new Rect(0, 0, sBitmap.getWidth(), sBitmap.getHeight()), new Rect(mObject.getX(), mObject.getY(), sBitmap.getWidth(), sBitmap.getHeight()), new Paint());
} else log("bitmap = null!");
}
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
The thread keeps running for some time, background elements are being drawn (even though my rotation does not work quite yet, but that's another story..), the background "seems" to move (like a side-scroller), but at some random point in time, without any ADB LogCat messages (not limited to the App but the whole LogCat output) - the thread simply stops. No more drawing. Nothing. I am not calling interrupt or setting isRunning to false, as the "Thread dead." message is not written into LogCat as well..
I do not know what's happening.
Thanks for your help.
You have:
timeDiff = System.currentTimeMillis();
// refresh, which takes some time I guess
timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());
so System.currentTimeMillis() will be later and therefore bigger than timeDiff. The term in brackets will be negative - so you will be adding onto the timePerFrame and timeDiff will grow not reduce.