lockCanvas() returns different canvases - java

Trying to draw something every ms on single canvas. I mean only adding details to canvas, not redrawing it all every frame. So this code gives me three different canvases. Third, then first again. Why?
public void run() {
this.run = true;
Canvas canvas = null;
while (run) {
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
Thread.sleep(delay);
draw(new Img(canvas, size));
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (canvas != null) {
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) {}
}
}
}
}
If it is android triple buffering - how to turn it off, or do something with it?
Android 4.2.1

If you like to preserve your previous draw you should draw them in an off-screen canvas and draw them to the canvas you got from lock canvas.
The puesd-code to illustrate the idea:
Bitmap offScreenBitmap = Bitmap.createBitmap(100,200,Bitmap.ARGB_8888);
Canvas offScreenCanvas = new Canvas(offScreenBitmap);
onScreenCanvas = this.surfaceHolder.lockCanvas();
//always draw to te offScreenCanvas
offScreenCanvas.drawXxxx
//copy the data to on-screen canvas you got from the lock
onScreenCanvas.drawBitmap(offScreenBitmap);
unlockAndPost(onScreenCanvas)
That should get your task done. Right?
Then, a little bit under the hood stuff:
Yes, android view (surface IS A view) has multiply buffers: one is used by apps for drawing and one is used by system for rendering and sometimes there is a third one when if the app can not finish drawing timely. No way to turn it off and you won't want to. And it is the reason you get different canvas when lock as you have already observed.

I would recommend against naming a boolean field, "run" in a Runnable implementation (in which the method returns void). Even if problems don't surface from the conflict, it's confusing. Maybe "running", or something (anything), would make more sense - easier to debug.
Don't use Object.wait when you are multi-threading. It won't always (generally, will not) act as you might expect.
You are most likely getting multiple instances of your Canvas member because somewhere (maybe in the Android framework, or maybe in your code... hard to tell), "new Canvas(args)" is being called while what you believe to be your only Canvas instance is out on another thread. While you have only one reference, more than one instance can be created.
I wouldn't recommend using synchronized(whatever) unless you are sure you need to do so.
Hang in there. This problem is very confusing - I worked through it last Spring and it wasn't easy or fun.
Hope any of the above helps in some way.
-Brandon

Related

Making 2048 game faster

Is there a way to make my 2048 game run faster?
I made a setting called high speed mode so that if moves were made really fast I would just skip the spawning, combining and moving animations, however even with that I am still usually one or two moves behind when I spam a bunch of keys at once.
Right now I have a tilePanel class to handle displaying my tiles, and use a timer(very basic code) with paintComponent(drawing the tiles constantly) to make sure it continually updates the board.
public void doAnimation() {
System.nanoTime();
Timer timer = new Timer(2, this);
timer.start();
}
The way I have structured my game is that I have an ArrayList of commands(ie pressing the right key adds "right" to the arraylist and eventually the arraylist gets to it and executes) I receive to make sure that it always does a move, spawns before doing the next move in the sequence.
To make sure the board continually updates itself, i made a very basic run thread:
public void run(){
while(true) {
if(canDoNewMove&&commands.size()>0&&parent.spawnsLeft==0) {
move(commands.get(0));
commands.remove(0);
canDoNewMove=false;
}
if(commands.size()>=2) {
board.isBehind=true;
}
else {
board.isBehind=false;
}
if(totalMovements==0&&moveDone) {
moveDone=false;
if(parent.changed) {
parent.spawn(parent);
}
canDoNewMove=true;
}
//moveDone=false;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}};
Thread sampleThread = new Thread(backGroundRunnable);
sampleThread.start();
}
Would reducing method calls produce a noticeable enough difference that the actions would finish right after I press the keys or is the problem within the tilePanel class that draws the board?
thanks guys

how to pause the execution of a function on a boolean variable?

I'm essentially envisioning a "traffic light" that has green and red lights. When the light is green we are allowed to doWork(). When the light is red I need to wait until doMaintenance() is complete before allowing doWork() to execute. I have done the following and it seems to behave correctly, but I'm wondering if this is a naive solution:
private volatile boolean lightIsGreen = true;
public void doSomeWorkIfLightIsGreen() {
while(!lightIsGreen) {
try {
Thread.sleep(1); // I'm not sure what value to put here
} catch (InterruptedException e) {
// Log exception
}
}
doWork();
}
And then there is a separate function in the same class that runs every so often:
private void doMaintenance() {
lightIsGreen = false;
doMaintenance();
lightIsGreen = true;
}
In my actual code, doMaintenance() is given several opportunities to successfully complete. If it cannot complete, then the entire application shuts down gracefully.
Is there a better / more elegant way of accomplishing this "traffic light" functionality?
Edit: I should mention that the doSomeWorkIfLightIsGreen() can be called from several threads and I do not want to cause those threads to have to execute one at a time. I think this means I cannot use Semaphores or ReentrantLock or any solution that required locking. Ultimately, what i'm trying to accomplish is to allow any thread calling doSomeWorkIfLightIsGreen() to successfully execute when the "light" is green but not allow any thread at all to execute when the "light" is red.

In Java, why is my multithreading not working?

At first I did this:
public SpaceCanvas(){
new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
int fcount = 0;
#Override
public void run() {
System.out.println("Update thread started!");
while(!Thread.interrupted()){
fcount++;
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
}
while(entities.iterator().hasNext()){
entities.iterator().next().update(fcount);
}
System.out.println("About to paint");
repaint();
System.out.println("Done with paints");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
in the initializer of a thing I call a SpaceCanvas.
However, that doesn't allow the canvas, and therefore the applet it is within, to be created, because the Thread doesn't actually run asynchronously. Then, I replaced ".start()" with ".run()" and the thread only ran once, but the SpaceCanvas initialized perfectly.
What did I do wrong, and how do I fix this?
I'm not sure this sort of code works the way you expect it to:
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
players.iterator() gets a new iterator for the players collection. If there are 0 items in the collection then it will be false but if there are any items, you will be in an infinite loop, creating a new iterator each time. The iterator() call inside of players generates another new iterator object as well.
I think you should doing something like:
Iterator iterator = players.iterator();
while (iterator.hasNext()) {
iterator.next().update(fcount);
}
This is the same with your entities loop as well. A better pattern (as of Java 5) is to use the for loop:
for (Player player : players) {
player.update(fcount);
}
Also, if multiple threads are accessing these collections, they have to be somehow synchronized. You can either use a concurrent collection or you have to make sure every access (read and write) is within a synchronized block.
synchronized (players) {
for (Player player : players) {
player.update(fcount);
}
}
...
// down in the outer thread
synchronized (players) {
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
Obviously the entities will need to be synchronized in the same manner.
In this millennium, use Swing (JApplet/JPanel) rather than AWT (Applet/Canvas)
When using Swing, establish a Swing Timer that calls repaint() every 500 msec.
(When using Swing/Timer) Don't call Thread.sleep(n) on the EDT (Event Dispatch Thread).
..can you draw on a JPanel?
Sure thing. To do so, override the paintComponent(Graphics) method. You might also extend a JComponent and do the same, but there are some quirks to dealing with a JComponent that make the JPanel the better choice to extend.
On the other hand, there is another approach entirely.
Create a BufferedImage of the size required for whatever custom graphic is needed.
Add the image to an ImageIcon.
Add the icon to a JLabel.
Add the label to the GUI.
On each Timer action.
Call image.getGraphics() to obtain the drawing surface.
Replicate what you might have done in paint() or paintComponent()
(If needed) erase all previous drawing.
Draw the current custom rendering.
dispose() of the Graphics instance of the image.
call label.repaint()

Correct use of wait()/notify() for a Tetris game

I’m writing a Tetris-like game for Android and I’m trying to implement the “real-time part”. I have something which seems to work, but I want to be sure that my implementation is correct.
What I want is:
The shapes are going down at a fixed rate (say that I want to wait n milliseconds each time the y of the shape is decremented)
The player can drop the shape at any time and the timer waiting for the n milliseconds must then be immediately interrupted and start again only for the next shape
When the shape is droped or when the shape cannot go down anymore, the game waits m milliseconds before creating another shape
The system have to be able to stop the thread at any time
What I am doing is the following (the system can stop the thread with interrupt()):
class TetrisThread extends Thread {
private int n = 3000; // for testing purposes, in the real game n will be smaller ;)
private int m = 1000;
#Override
public void run() {
doDraw();
while(!interrupted())
{
try {
synchronized (this) {
wait(n);
}
doPhysics();
doDraw();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// This method is the one which will drop the shape, it is called from another thread
synchronized public boolean onTouch([…]) {
[…]
// The shape has to be dropped
dropShape();
notify();
[…]
}
private void doPhysics() throws InterruptedException {
[…]
// The shape cannot go down or has been dropped
sleep(m);
createNewShape();
[…]
}
}
In particular, the part synchronized(this) { wait(n); } looks funny because if I understand correctly this will take a lock on this and release it immediately.
But wait() requires to be used in a synchronized(this) block (why?) and I cannot either synchronize the whole run() method, because then if I try to drop three times the shape during the sleep(m) call, then the three next shapes will be automatically dropped (which is not what I want).
Does this seem correct to you?
Do you have any correction, advice, or remark?
Thank you :-)
The wait() method is used to make the current running thread to wait the object invoking wait() invoke notify() (in this case this). The synchronized(this) part needed to make sure only one thread at that time accessing this.
You can't synchronize the whole run() method, because the run() is from the parent (Thread) class and the parent didn't use synchonized in the declaration.
I don't know how to solve your other problem because I don't get how your program works right now.

do I need to close an audio Clip?

have an application that processes real-time data and is supposed to beep when a certain event occurs. The triggering event can occur multiple times per second, and if the beep is already playing when another event triggers the code is just supposed to ignore it (as opposed to interrupting the current beep and starting a new one). Here is the basic code:
Clip clickClip
public void prepareProcess() {
super.prepareProcess();
clickClip = null;
try {
clipFile = new File("C:/WINDOWS/Media/CHIMES.wav");
ais = AudioSystem.getAudioInputStream(clipFile);
clickClip = AudioSystem.getClip();
clickClip.open(ais);
fileIsLoaded = true;
} catch (Exception ex) {
clickClip = null;
fileIsLoaded = false;
}
}
public void playSound() {
if (fileIsLoaded) {
if ((clickClip==null) || (!clickClip.isRunning())) {
try {
clickClip.setFramePosition(0);
clickClip.start();
} catch (Exception ex) {
System.out.println("Cannot play click noise");
ex.printStackTrace();
}
}
}
The prepareProcess method gets run once in the beginning, and the playSound method is called every time a triggering event occurs. My question is: do I need to close the clickClip object? I know I could add an actionListener to monitor for a Stop event, but since the event occurs so frequently I'm worried the extra processing is going to slow down the real-time data collection.
The code seems to run fine, but my worry is memory leaks. The code above is based on an example I found while searching the net, but the example used an actionListener to close the Clip specifically "to eliminate memory leaks that would occur when the stop method wasn't implemented". My program is intended to run for hours so any memory leaks I have will cause problems.
I'll be honest: I have no idea how to verify whether or not I've got a problem. I'm using Netbeans, and running the memory profiler just gave me a huge list of things that I don't know how to read. This is supposed to be the simple part of the program, and I'm spending hours on it. Any help would be greatly appreciated!
Michael
yes, closing is necessary
myClip.addLineListener(new LineListener() {
public void update(LineEvent myLineEvent) {
if (myLineEvent.getType() == LineEvent.Type.STOP)
myClip.close();
}
});
or by
if (!myClip.isRunning())
myClip.close();
In my application (written before the advent of util.concurrent), this is the clip closing mechanism.
public static final Vector<Clip> vector = new Vector<Clip>();
static final int vector_size = 5;
// typically called before calling play()
static synchronized void consolidate() {
while (vector_size < vector.size()) {
Clip myClip = vector.get(0);
if (myClip.isRunning())
break;
myClip.close();
vector.remove(0);
}
if (vector_size * 2 < vector.size())
System.out.println("warning: audio consolidation lagging");
}
public static void play(final File myFile) {
try {
AudioInputStream myAudioInputStream = AudioSystem.getAudioInputStream(myFile);
final Clip myClip = AudioSystem.getClip();
vector.add(myClip);
myClip.open(myAudioInputStream);
myClip.start();
} catch (Exception myException) {
myException.printStackTrace();
}
}
As one of the comments suggest, it may delay the playback of new clips, but I cannot remember as a few ms delay were not important in my application.
Memory leaks in Java have to do with objects that are still being referenced even after their useful lives have ended. In many cases, this will be due to something like repeatedly making 50 objects but only eliminating references to 49 of them later on.
Nothing like that seems to be going on in your code. Since prepareProcess() only runs once, it's not highly suspect. That leaves playSound(), which doesn't contain any object instantiation at all, much less a faulty reference elimination loop.
The caveat is that I'm not sure what goes on behind the scenes in your sound clip object, and it's hard to check because majuscule-C Clip is only an interface. Unless you're using third-party code, though, I'd be very surprised to find a leak there.
Long story short, I wouldn't worry about it unless and until you actually see something like an OutOfMemoryError.

Categories