Codename one container.revalidate() IndexOutOfBoundsException is thrown sometimes - java

I've met such a problem. I'm getting IndexOutOfBoundsException when I'm calling .revalidate on container.
I have a Runnable class, which increases or decreases margin of component. I'm using it to make kind of drawer animation. Everything, except this exception, works perfectly. Ans the exception is thrown randomly. I can run "animation" method several times before I get this exception logged to the console.
And after that exception app is working fine. Only container is shown incorrect.
Here's error log:
Exception in thread "Thread-15" java.lang.IndexOutOfBoundsException: Index: 5, Size: 1
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
at com.codename1.ui.Container.getComponentAt(Container.java:1083)
at com.codename1.ui.Container.doLayout(Container.java:1054)
at com.codename1.ui.Container.layoutContainer(Container.java:1043)
at com.codename1.ui.Container.doLayout(Container.java:1056)
at com.codename1.ui.Container.layoutContainer(Container.java:1043)
at com.codename1.ui.Container.doLayout(Container.java:1056)
at com.codename1.ui.Container.layoutContainer(Container.java:1043)
at com.codename1.ui.Container.doLayout(Container.java:1056)
at com.codename1.ui.Container.layoutContainer(Container.java:1043)
at com.codename1.ui.Container.revalidate(Container.java:835)
at util.classes.AnimationRunnable.run(AnimationRunnable.java:75)
at java.lang.Thread.run(Thread.java:745)
Why can it be? What can be the problem?
Thank you!
UPD:
Here's my runnable class:
Removed needless code:
public class AnimationRunnable implements Runnable {
private float marginFrom = 0;
private float marginTo = 0;
private Container bottomContainer;
private int screenHeight;
public AnimationRunnable(Container bottomContainer, int screenHeight, float marginFrom, float marginTo) {
this.marginFrom = marginFrom;
this.marginTo = marginTo;
this.bottomContainer = bottomContainer;
this.screenHeight = screenHeight;
}
#Override
public void run() {
boolean finished = false;
boolean directionUp = marginFrom > marginTo; // true = up; false = down
Container parent = bottomContainer.getParent();
while (!finished) {
// if distance between current margin and destination margin is < 10, finish
if (Math.abs(marginFrom - marginTo) < 10) {
finished = true;
} else {
// if container size is increasing
if (directionUp) {
// if current margin is less than destination margin
if (marginFrom <= marginTo) {
marginFrom = marginTo;
finished = true;
} else {
// else - modify current margin to be closer to destination margin
marginFrom -= Math.ceil((marginFrom - marginTo) / 6);
}
} else {
// if current margin is less than destination margin
if (marginFrom >= marginTo) {
marginFrom = marginTo;
finished = true;
} else {
// else - modify current margin to be closer to destination margin
marginFrom += Math.ceil((marginTo - marginFrom) / 6);
}
}
}
// Setting style to container (in case if container's current style is changed)
Style defaultStyle = bottomContainer.getStyle();
bottomContainer.getStyle().setMargin(Component.TOP, Math.round(marginFrom));
// Setting default style to all container states
// HERE EXCEPTION IS THROWN
// Revalidating either parent, or container itself
if (parent != null) {
parent.revalidate();
parent.repaint();
} else {
bottomContainer.revalidate();
bottomContainer.repaint();
}
try {
// Wait 25ms to make animation smooth
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// revalidate once more after loop is over
if (parent != null) {
parent.revalidate();
parent.repaint();
} else {
bottomContainer.revalidate();
bottomContainer.repaint();
}
return;
}
}
UPDATE
CallSerially doesn't show the animation, it just waits, and updates the UI, when animation runnable. But calling Display.geInstance().invokeAndBlock() with this animation runnable works as wanted without throwing exceptions.

You are changing UI not on the EDT, which can cause issues and conflicts between the thread you are running and the EDT(Event Dispatch thread).

Related

Thread not behaving as expected after rewrite

I'm writing an android app to measure display lag on tvs using the mirror function on the video out. After many revisions, my code got too complex for its own good, so I scraped it and did a rewrite. My issue is that it is not behaving as expected. The square is not blinking, and the time is 0.0 and the rating is excellent. i have tested changing the ui via the thread by making the square turn different colors, that worked fine. Can someone tell me what the issue is and how to fix it? The way the app works is that you hook the device to a tv and it mirrors the display. then it changes the color of a square in the app and dose a time stamp, then it wait till the camera detects a change then dose another time stamp. using both time stamps you can figure out the delay of the tv. I have it in a loop because the camera only captures at 15ish fps, so I need to run the test multiple times to get an accurate result. The issue is that it always shows up as 0.0ms, that is an impossible number because the lag on most consumer tvs is 9ms. I get the RGB values from each camera frame.
class lagTestThread extends Thread {
#Override
public void run () {
long lagStartTime;
long lagEndTime;
long tempResult;
final double rating;
int x;
long testResult = 0;
int cnt;
for (cnt = 0; cnt >= 100; cnt++){
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(000, 000, 000));
}
});
while (redVal >= 10.0 && blueVal >= 10.0 && greenVal >= 10.0) {
x = 0;
}
redVal = 0;
blueVal = 0;
greenVal = 0;
lagStartTime = System.nanoTime(); //start lagTimer start
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(255, 255, 255));
}
});
while (redVal <= 100.0 && blueVal <= 100.0 && greenVal <= 100.0) {
x = 0;
}
lagEndTime = System.nanoTime(); //start lagTimer end
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(000, 000, 000));
}
});
tempResult = (lagEndTime - lagStartTime);
if (tempResult <= testResult && tempResult != 0) {
testResult = tempResult;
}
}
rating = ((double) testResult) / 1000000.0;
final String finalResultString = String.valueOf(rating);
runOnUiThread(new Runnable() {
#Override
public void run() {
lagTime.setText(finalResultString);
if (rating <= 17.0) {
lagRating.setText("Excellent");
} else if (rating <= 34.0) {
lagRating.setText("Great");
} else if (rating <= 51.0) {
lagRating.setText("Average");
} else {
lagRating.setText("Bad");
}
}
});
}
}
I call it like this
public void startTest(View view) {
lagTestThread lagTest = new lagTestThread();
lagTest.start();
}
redVal, blueVal, greenVal declaration
#Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
double[] rgb = inputFrame.rgba().get(100, 100);
redVal = rgb[0];
blueVal = rgb[2];
greenVal = rgb[1];
Log.i("", "red:" + rgb[0] + " green:" + rgb[1] + " blue:" + rgb[2]);
return rgbMat;
}
The runOnUiThread() causes the Runnable to be posted to the UI thread, at which point the function returns immediately. The Runnable executes at some later time.
Your code is posting events to the UI thread and checking the system time, which means you're calculating how long it takes to post events to the UI thread, not how long it takes them to run. Also, because all the events are queued up behind one another, it's likely they will all execute in the same frame, so you will only see the result of the last setBackgroundColor() call.
If you really want to divorce your display and timing code from the UI thread, you should consider doing this with a SurfaceView, which can be updated independently of the UI thread. (The down side of SurfaceView is that it's a lot more complicated to work with than a custom View.)

How can you make your program sleep so that the GUI can catch up to what's happening?

I'm making a snake game(for those who don't know) where the snake is controlled by an AI using different algorithms to catch the food. The difference with the regular game is that the snake doesn't move unless a command has been sent by the AI.
My problem is that as soon as I run the AI, the AI creates a stack of commands to be executed to catch the food but my GUI just freezes; probably because it can't keep up with the amount of repaints that the move stacks cause. Through console logs, I can see that AI and the game logic is still running.
I tried to do Thread.sleep() after each move but I guess this just makes the entire program including the GUI sleep. I also have a Timer for my paintComponent but that doesn't seem to change anything.
How can you make your program sleep so that the GUI can catch up to what's happening?
EDIT:
Ok guys, I tried your solutions and it's still not working as it should. I don't really want to just dump the code here but I'm really lost. I have a timer that should repaint on a 140 millisecond interval(that's the value of DELAY), the commands are sent on a different thread which goes to sleep after each key press for 1000 milliseconds and I call repaint() after each call to move()... Here is relevant code(the original code without my modifications here):
private void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
for (int k = blockNb - 1; k > 0; k--) {
locateBlock(k, apple_x, apple_y);
}
if (blocks) {
locateBlock(0, apple_x, apple_y);
}
timer = new Timer(DELAY, this);
timer.start();
startAi();
}
// AI CONTROLLER
public void startAi() {
Ai theAi = new Ai();
String move = "";
switch (ai) {
case "BFS":
move = theAi.bfs(this);
break;
}
//AI returns a string where each char is a move command
autoMove(move);
}
public void autoMove(String move) {
try {
Robot robot = new Robot();
System.out.println(move);
if (move != "#No") {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < move.length(); j++) {
if (move.charAt(j) == 'l') {
robot.keyPress(KeyEvent.VK_LEFT);
robot.keyRelease(KeyEvent.VK_LEFT);
}
if (move.charAt(j) == 'r') {
robot.keyPress(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_RIGHT);
}
if (move.charAt(j) == 'u') {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
if (move.charAt(j) == 'd') {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread.run();
}
} catch (AWTException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int j = 0; j < blockNb; j++) {
g.drawImage(block, block_x[j], block_y[j], this);
}
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(ball, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
// gameOver(g);
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
repaint();
}
}
private class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
move();
checkApple();
checkCollision();
repaint();
}
}
EDIT 2: Also, I just wanted to point out that I tried to move without relying on a robot but to no avail.
Part 1:
Difference bettween Thread.sleep:
When you use it in main Thread(the Thread which java use to run the program)
then your whole program just freeze for that reason.
When you use A Thread for example(follow code)
new Thread(new Runnable(){
public void run(){
//do something...
while(flag==false)
Thread.sleep(a given time) //it need and try catch
else
//do your move
});
then only this Thread freeze (for a given time) or (Whatever you transform it to freeze).
In your case you can use a flag so every time a commant is hitten by user
the flag is going true and then again false to keep stopped the part of the
game you want but the main Thread your programms need to work still works
(if it is a window or anything...)
Part 2:(Basic form of your Thread)(The flag i use must be seen by all Methods)(public or private)
new Thread(new Runnable() {
public void run() {
flag=true;
while(flag==true){
if(move.equals("yes")){
//your code
move="no";
}else
Thread.sleep(20); //Sleep For a While(and then check again)
}
//That means that your Thread will run all over your game
//until game over (when game over just do the flag=false;)
//and The Thread will stop-exit
}});
*About Repaint Method(Dont call the repaint method too fast)
Call it only when the player make a move(this is the time that the frame
need to be repainted[Ok if you have .gif images in your game just dont see this]
Part 3:(When i made a similar game what i did)
Before some months i tried a similar game.The basic idea was a player who must past a labirinth so....
For each level i had one class like this...
public abstarct class Level2(){
//The game was into a panel like your.
//Here i added .setFocusable and .addKeyListener to panel
//Here it was an
public void actionListener(){
//The actionListener checked if the player found the door(for next level)
//Here it was the repaint so every time something happened repaint()
repaint();
}//End of Action Listener
//Use the paint or paintComponent what you need..
public void paint[or paintComponent](Graphics g){
//the 'squares' and the icons the had to be *repainted* again
}
//Here i had an extra class into this for the KeyListeners
//And I added the KeyListener like your game(up,down,left,right)
//I i said before i added this KeyListener to the panel
private class TAdapter extends KeyAdapter {
//KeyPressed,Released...etc
}
}
Thats the basic idea and for your game i think.
The Thread it's an extra option i can't help more you must find the way...
You should have a single "update" looped, from which your execute update commands and repaint request.
A simple approach would be to use a Swing Timer, which can trigger updates to a listener at regular intervals. It has the benefit of been triggered within the context of the EDT making it safe to update the UI from within. See How to use Swing Timers for more details
A more complex approach would be to use a Thread, which contained some kind of loop. This would perform the required updates and schedule repaint, but you'd need to insert Thread.sleep in to allow time for the updates to occur at a regular bases. The problem with this is you will need to synchronise your updates so that you don't update the model while painting is occurring as well synchronise you updates to the UI with the EDT
You need to have some sort of game scheduler loop and an understanding of how it works.
Here is some example code for java swing:
http://staticvoidgames.com/tutorials/swing/swingTimers
Another way to simplify things along with the scheduler is to make your game turn based at first. That is when the player moves 1turn (ie input) the game does all its processing and blocks on user input till the processing is done (ie single loop).
Every time your game AI outputs a new move, you need to call paint, but you also need to wait for whatever event is called when the painting is done before you output your next move, and you may want to wait like a second longer or something, play around with it
pseudo code
def fun 0 // entry point for program
// hook paint done event to func 1
call fun 2
def fun 1 // event handler method for when painting done
call fun 2
def fun 2 // function that does AI work
// do game logic
// call paint

How to stop frames per second from dropping?

Okay, so why would my frames per second drop at a random time while playing the game? and what can I do to fix it. Below im going to show the code that I have with the engine that was built.
public Engine() {
Log.d("Engine","Engine constructor");
p_view = null;
p_canvas = null;
p_thread = null;
p_running = false;
p_paused = false;
p_resume = false;
p_paintDraw = null;
p_paintFont = null;
p_numPoints = 0;
p_typeface = null;
p_preferredFrameRate = 40;
p_sleepTime = 1000 / p_preferredFrameRate;
p_pauseCount = 0;
p_group = new LinkedList<Sprite>();
}
/**
* Runnable.run thread method (MAIN LOOP)
*/
#Override
public void run() {
Log.d("Engine","Engine.run start");
ListIterator<Sprite> iter=null, iterA=null, iterB=null;
Timer frameTimer = new Timer();
int frameCount=0;
int frameRate=0;
long startTime=0;
long timeDiff=0;
while (p_running) {
// Process frame only if not paused
if (p_paused) continue;
// Calculate frame rate
frameCount++;
startTime = frameTimer.getElapsed();
if (frameTimer.stopwatch(1000)) {
frameRate = frameCount;
frameCount = 0;
//reset touch input count
p_numPoints = 0;
}
// Call abstract update method in sub-class
update();
/**
* Test for collisions in the sprite group.
* Note that this takes place outside of rendering.
*/
iterA = p_group.listIterator();
while (iterA.hasNext()) {
Sprite sprA = (Sprite)iterA.next();
if (!sprA.getAlive()) continue;
if (!sprA.getCollidable()) continue;
/*
* Improvement to prevent double collision testing
*/
if (sprA.getCollided())
continue; //skip to next iterator
//iterate the list again
iterB = p_group.listIterator();
while (iterB.hasNext()) {
Sprite sprB = (Sprite)iterB.next();
if (!sprB.getAlive()) continue;
if (!sprB.getCollidable()) continue;
/*
* Improvement to prevent double collision testing
*/
if (sprB.getCollided())
continue; //skip to next iterator
//do not collide with itself
if (sprA == sprB) continue;
/*
* Ignore sprites with the same ID? This is an important
* consideration. Decide if your game requires it or not.
*/
if (sprA.getIdentifier() == sprB.getIdentifier())
continue;
if (collisionCheck(sprA, sprB)) {
sprA.setCollided(true);
sprA.setOffender(sprB);
sprB.setCollided(true);
sprB.setOffender(sprA);
break; //exit while
}
}
}
// begin drawing
if (beginDrawing()) {
// Call abstract draw method in sub-class
draw();
/**
* Draw the group entities with transforms
*/
iter = p_group.listIterator();
while (iter.hasNext()) {
Sprite spr = (Sprite)iter.next();
if (spr.getAlive()) {
spr.animate();
spr.draw();
}
}
/**
* Print some engine debug info.
*/
int x = p_canvas.getWidth()-150;
p_canvas.drawText("ENGINE", x, 20, p_paintFont);
p_canvas.drawText(toString(frameRate) + " FPS", x, 40,
p_paintFont);
p_canvas.drawText("Pauses: " + toString(p_pauseCount),
x, 60, p_paintFont);
// done drawing
endDrawing();
}
/*
* Do some cleanup: collision notification, removing
* 'dead' sprites from the list.
*/
iter = p_group.listIterator();
Sprite spr = null;
while (iter.hasNext()) {
spr = (Sprite)iter.next();
//remove from list if flagged
if (!spr.getAlive()) {
iter.remove();
continue;
}
//is collision enabled for this sprite?
if (spr.getCollidable()) {
//has this sprite collided with anything?
if (spr.getCollided()) {
//is the target a valid object?
if (spr.getOffender() != null) {
/*
* External func call: notify game of collision
* (with validated offender)
*/
collision(spr);
//reset offender
spr.setOffender(null);
}
//reset collided state
spr.setCollided(false);
}
}
}
// Calculate frame update time and sleep if necessary
timeDiff = frameTimer.getElapsed() - startTime;
long updatePeriod = p_sleepTime - timeDiff;
if (updatePeriod > 0) {
try {
Thread.sleep( updatePeriod ); // i notice this is called when frames are low
}
catch(InterruptedException e) {}
}
}//while
Log.d("Engine","Engine.run end");
System.exit(RESULT_OK);
}
public void setFrameRate(int rate) {
p_preferredFrameRate = rate;
p_sleepTime = 1000 / p_preferredFrameRate;
}
So this is not the entire engine, but it is everything that deals with the frames Why is it randomly dropping? What I am noticing that thread.sleep is being called when the frames drop below 15. I am using a nexus 5 to test this running on android 4.4.2, and My question here is How do I stop the frames from dropping that low and having it sleep especially after calling a recreate(); method when you lose the game?
Just take out the Thread.Sleep statement altogether. Or just pass "0" into the Sleep call (if you are trying to yield cycles to other threads and processes). On each cycle of the run() loop, calculate how much time actually elapsed and update your simulation based on this value. In other words, don't try to force a hard-coded frame rate.
The device has an upperbound on frame rate (60fps on my device). So you'll likely be sleeping a little during each loop anyway.

Javafx - Syncronization delay - card flips

I'm actually working on a memory game and I'm stuck at the point where I should write the gameplay-part of the game.
So:
I have an array of N card objects. Each object has an attribute called cardNum - an identifier. I think I should write an actionListener on that array, so when I flip a card, it puts the flipped card's cardNum in an array of two elements and if the two elements of the array are equal, a pair is found.
The problem is that I just don't know how to get the last flipped card's cardNum.
Any help would be appreciated.
Here's the way I tried:
private void easyGame(Card[] cards) {
int flippedCards = 0;
int card1;
while(flippedCards != 24) {
for(int i=0; i<cards.length; i++) {
if(cards[i].getIsFlipped())
flippedCards ++;
}
if(flippedCards % 2 == 0 && flippedCards > 0)
for(int i=0; i<cards.length; i++) {
card1 = getCardIndByCardNum(cards[i].getCardNum(), cards, i);
if(!cards[card1].getIsFlipped()) {
for(int j=0; j<cards.length; j++) {
if(cards[i].getIsFlipped())
cards[i].flip();
}
flippedCards = 0;
break;
}
}
}
}
The problem is that if I call this method, the game won't be drawn. May I use use threads somehow?
EDIT
Here is how I get the indexes of the clicked cards, and I call it in the UI:
private void setCardHandlers() {
for(final Card card : cards) {
card.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
clickedCardInd = getChildren().indexOf(card)-1;
}
});
}
}
Than here is how I am using it:
setOnMouseReleased(new EventHandler<MouseEvent> () {
#Override
public void handle(MouseEvent t) {
int cardIndex = clickedCardInd; // get index of what user clicked
clickedCardInd = -1;
if (cardIndex != -1 && moveRequestedFlag) { // our controller waits for the move
// get the position and report
moveRequestedFlag = false; // we handled the move
//System.out.println(cardIndex);
nextMove.setMove(cardIndex); // this will unblock controller's thread
}
}
});
It has a delay on fliping cards, also in the easyGame the requestMove method sets both indexes to the same.
I would recommend splitting you responsibilities a bit into Model/View/Controller modules, which, in simplest case would look like :
Model - your game current state and data, i.e. cards array Cards mCards = new Cards[24];
View - your UI, that can reflect current state of mCards(model) on screen in Main thread
Controller - your main game logic. This is most complex part, responsible for
requesting/handling user move,
updating mCards(model) based on user move,
Requesting UI to re-draw.
Contoroller's code (easyGame method) should run on separate thread to not block the UI.
Below I sketched a skeleton code that should fit your requirements :
class Game {
/*
* controller - main logic
*/
void startEasyGame() {
// initialize cards array, shuffle if needed
// we start with zero cards flipped
int flippedCards = 0;
// main loop
while (flippedCards != mCards.length) {
// 1. show updated UI
mBoard.showUpdatedCards();
// 2. request player move
// and block current thread to wait till move is done
// the result of the move - index of the card
int index1 = requestMove();
// temporarily flip first card face-up
mCards[index1].flip();
// show it on screen
mBoard.showUpdatedCards();
// same for second card
int index2 = requestMove();
mCards[index2].flip();
mBoard.showUpdatedCards();
// 3. check the result
if (mCards[index1].getCardNum() == mCards[index2].getCardNum()) {
// hooray, correct guess, update count
// possibly show some encouraging feedback to user
flippedCards += 2;
} else {
// incorrect, flip cards back face down
mCards[index1].flip();
mCards[index2].flip();
}
} // end of while loop
// game ended -> show score and time
mBoard.showResult();
}
}
EDIT
Extra details on how to await for result from UI thread :
int requestMove() {
// 1. show user prompt to make a move
// ...
// 2. construct latch to wait for move done on UI thread
mBoard.moveRequestedFlag = true;
NextMove nextMove = new NextMove();
mBoard.nextMove = nextMove;
// 3. await for move and get the result
return nextMove.getMove();
}
then, somewhere in UI code :
// handling card onClick somewhere on UI thread
if (mBoard.moveRequestedFlag) { // our controller waits for the move
// get the position and report
int cardIndex = ... // get index of what user clicked
mBoard.moveReqestedFlag = false; // we handled the move
mBoard.nextMove.setMove(cardIndex); // this will unblock controller's thread
}
and NextMove utility class to sync threads :
public class NextMove {
private volatile int mCardIndex;
private final CountDownLatch mMoveReady = new CountDownLatch(1);
public int getMove() throws InterruptedException {
mMoveReady.await();
return mCardIndex;
}
public synchronized void setMove(int selectedCardIndex) {
if (mMoveReady.getCount() > 0) {
mCardIndex = selectedCardIndex;
mMoveReady.countDown();
}
}
}

Reasons for my drawing thread to suddenly stop?

#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.

Categories

Resources