UI not updating smoothly due to a background Thread - java

I am writing an android game and here is what i have:
Game loop is implemented as:
I have made a custom view which extends the view.Then inside my onDraw() method, i call invalidate();
MainActivity:
Here i make an instance of a custom view and use setContentView() to set that as my current view.
I also use OnTouch() method to get touch events
Everything was working fine and smoothly till i did this:
I made a new class Graphthread and inside the run method, i created a loop.
public class Graphthread extends Thread
{
#Override
public void run() {
while(true)
{
}
}
}
Then i created an instance of this in my MainActivity
Graphthread gth = new Graphthread();
and used gth.start() in my onCreate method.
Now following happened:
The game did not run smoothly.Or i should say it was like..run for sometime..freeze for a few milliseconds...run again ...freeze again and so on.
What is happening?

Slight jitters like that sounds like garbage collection. If your background thread (or something else) is consuming a very large amount of memory, the GC may need to run more often then expected. That would cause momentary jitters such as you described.

Try more suitable approach for games: use SurfaceView and background thread to draw on it. This should free you from stuttering, cased by irregular message processing by main thread.
onDraw hack, from my point of view, suitable only if you want to animate something inside a regular app (not game), and animation framework has little use for you. Panning and scaling image for example.

Related

JavaFX window is not opened immediately

I've created a visualizer in JavaFX for a problem I'm solving, and currently I can get it to show up after the calculations in my application are done, but I would like the window to first be opened and then run the calculations, so I can animate the visualization during the computations.
This is the code for creating an instance of the problem, showing the visualizer and performing the calculations:
public static void run(Visualizer v) {
readInput();
if (v != null) {
v.resizeCanvas(rectangles);
v.drawAllRectangles(rectangles);
v.show();
}
calculateArea();
System.out.println(totalArea);
}
The Visualizer class extends javafx.application.Application and utilizes a JavaFX Canvas. calculateArea() simply runs a static method which performs some calculations.
What currently happens when I run my program is:
It waits for input on stdin
The computations are run
The visualization is displayed
What I want:
It waits for input on stdin
The visualization is displayed
The computations are run
So for some reason the displaying of the visualization is delayed even though I call v.show() before calculateArea().
My first hunch would be to run the calculations in a new thread, but according to
the documentation "The JavaFX scene graph, which represents the graphical user interface of a JavaFX application, is not thread-safe and can only be accessed and modified from the UI thread also known as the JavaFX Application thread."
I tried putting a Thread.sleep(3000) right after v.show(), and what happened was that my program just waited 3 seconds before running calculateArea() followed by the window being displayed.
Thanks for any input!
You should call your calculation method in a separate thread (as suggested by #Selim) launched in the applications start() method.
If your calculation method directly changes graphical content on screen (which it should not do BTW...) you need to pass this graphics code (not the calculation itself) to Platform.runLater().

Java Android studio: change an attribute of a View inside its own listener

I have a question about the Android Studio:
I have an Image view. Let's call it ImageView. I call the method setOnCLickListener on this ImageView with a listener new View.OnclickListener().
In the method onClick() of this listener, I change an attribute (the color, the image itself...) of this imageView. For example, I change the image with imageView.setImageResource(R.drawable.new_image). I then wait for 10 sec with Thread.sleep(10000). I then set back the previous image with imageView.setImageResource(R.drawable.previous_image).
Here is my question:
I expect the ImageView to change its image for 10 sec and then have the previous image back. However, I see no change on this ImageView. I only see the first image...Could someone explain me why?
I hope I was clear enough...Thank you in advance for your help :) !!
R.id.drawable.previous_image ?. It should be R.drawable.previous_image
First of all, you should read the Processes and Threads guide to understand how threading works on Android.
If you're done with with that, you'll understand that what you do is really bad because you freeze the main (UI) thread which means the application will not respond to any events until the 10 seconds pass. This also results in an ANR (Application Not Responding) dialog which is pretty bad UX.
You basically need to delegate the waiting period to another thread (or a queue at least), then when the time comes, go back to the UI thread and set whatever view attribute you want. There are many ways to achieve this, you should read Communicating with the UI Thread for more details. Here's just a quick sample:
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// write here what you want to happen in 10 seconds on the UI thread
}
}, 10000); // 10s = 10,000ms
Here are some notes though:
Save the Runnable you create here to a variable because if the user navigates away from this screen within the 10 seconds, it will still run the code inside, which might result in various exceptions. In this case you need to remove that Runnable from the handler by calling handler.removeCallbacks(runnable); when the user leaves the screen.
Don't create a new Handler instance every time the click event happens. Create it in the Activity's onCreate(...) method and use that instance in the rest of the screen.
You could create the Handler without the Looper parameter, which would create the handler for the current thread's Looper and that would be fine now since it's being created on the UI thread. However, I decided it's better to show you the safer way since you might end up doing something similar on a background thread that could result in unexpected behavior if you don't understand the threading yet.

Libgdx on desktop, how to handle disposing when window is closed

I'm using libgdx (com.badlogic.gdx.Game and Screens and that stuff) to make a game. I have the following problem: on desktop, when I close the window (from the cross on top), of course the application closes. But I would like to go back to menu screen and dispose there, since I do disposing of resources there (via asset manager). I have buttons for exiting in the game and if exiting is done that way, it's fine. The trouble is that the red cross can be pressed. So how could I handle disposing properly in that case?
On the android version, I catch the back key and handle leaving different parts of the game and the whole game in my own way. And there it works OK.
Another related question I have:
On desktop the application cannot get stopped and then disposed (on it's own, without user explicitly exiting it) like the android version can (the android life cycle), right? So is it a good idea, if I do a temporary save on pause() and restore game state from that on resume(), that I don't restore on desktop (since the restoring isn't a complete restore and I don't want restoring to happen if, on desktop, the window is just minimized (as I noticed, pause()/resume() gets called when minimizing/restoring window )).
Hope this wasn't too unclear :D. I've tried to google for answers but don't seem to find anything. Any help is much appreciated.
I suggest using the libgdx life-cycle methods
To dispose you should use the dispose() method. You don't need to call dispose yourself! It will be called automatically when the application gets destroyed, see documentation:
dispose () Called when the application is destroyed. It is preceded by a call to pause().
So just implement the dispose method in your Screens:
#Override
public void dispose () {
//your code needs to get added here, like for example:
stage.dispose();
texture.dispose();
//etc..
}
Update: Note that dispose() of AppliacationListener gets called automatically, not dispose() of Screen, see comment of Springrbua
You can call dispose() of your Screen by calling it explicitly from your Game Class dispose() like this
MyScreen Class:
public class MyScreen implements Screen {
// Not going to write all other methods that need to be overridden
#Override
public void dispose() {
// Clear you Screen Resources here
}
}
MyGame Class:
public class MyGame extends Game {
// Not going to write all other methods that need to be overridden
#Override
public void create() {
setScreen(new MyScreen());
}
#Override
public void dispose() {
// Clear you Screen Explicitly
getScreen().dispose();
}
}
Hope this helps
As mentioned above, the Screen interface contains a dispose method. Additionally, the dispose method of Game can be overridden to dispose of the current screen automatically. However, there is a reason this is not the default. Let's say you have multiple Screens - Screen1and Screen2. Screen1 was active, then changed the screen to 2. The game is then exited, and the dispose method is called, which calls the current screen's dispose method - leaving screen 1 alone.
My preferred method is to have the game keep track of screens set by overriding the setScreen method and adding a Screen[] screens, a boolean[] scrDiss, and an index. When dispose is called on Game, it checks through all screens set, checks if previously disposed, and disposes if not. Additionally, the Screen dispose methods should call a method on the Game that finds it in the array, and marks it disposed. This way, screens can be disposed before the end of the Game, but when Game is disposed, all Screens will be as well.
Call dispose on all your screens when your application is disposed.

How can I get wait/sleep to work the way I want in java?

I'm trying to accomplish something very simple. First, load my layout (main.xml). Then wait 1 second, modify an image, wait 1 second and modify it to a third image. (My end goal is more complex, of course, but I can't even get this to work).
Basically, I get a black screen when the app loads. It stays that way until all the waiting is over, then it shows the final image. Here's my code:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageCard[0] = (ImageView)findViewById(R.id.imageView11);
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.secondimage));
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.thirdimage));
ImageCard[0] is the image I'm trying to change. It loads in main.xml and shows fine if I remove the rest of the code.
If I change the sleep time to 5000, it then takes 10 seconds before it finally comes away from the black screen and shows the third image. This is how I know it's not just loading slow, but that it's actually waiting.
It's like it's not running sequentially. I'm no java expert, so I'm assuming I'm doing something dumb...
Thanks for any help!
I think you are blocking the UI Thead. Try Handler.postDelayed on a static Handler object.
Ok heres your problem, you can never do a sleep(...) when you are in the UIThread. The UIThread is never suppose to be locked up, it causes a lot of very bad things to happen in android. But there is a very easy way around it, just get off the UIThread and hop back on it when you need to. Heres what i would recommend:
public void onCreate(...)
{
super.onCreate(...);
myActivity.setContentView(R.layout.main);
new Thread(this).start();
}
public void run()
{
try
{
changeLayout(R.layout.main2);
Thread.sleep(5000);
changeLayout(R.layout.main3);
Thread.sleep(10000)
changeLayout(R.layout.main4);
}catch(Exception e){}
}
public void changeLayout(int id)
{
this.id = id;
myActivity.post(new Runnable()
{
public void run()
{
myActivity.setContentView(id);
}
});
}
private int id;
Of course with this example your class must implement Runnable to work. Only the UIThread can access the UI, no other thread can. Thats why you have to hop on and off the UIThread. Hope this worked!
Try adding ImageCard[0].invalidate() when you want it to draw.
I think Hovercraft Full of Eels is pointing you in the right direction. Essentially, you're not doing any multi-threading, you're telling the main thread to wait which means that it never completes the drawing. I'm not sure about Android, but Swing uses double-buffering by default (to avoid screen flashes), but that means that what is drawn, is actually drawn on to a buffer, not the window itself which is why you don't see anything. You could try disabling the double buffering (which Android is likely using) but that could cause other issues.
You might want to actually do multi-threading, or, I'm sure Android likely has a Timer component. If it does, I'd suggest you use it over Thread.sleep or actual multi-threading. Using a Timer you can have it fire an event after one second. That event will execute the other code.
do you have that code in constructor or in init() function? if yes, draw just the first picture and the Thread.sleep() function move after the place which the constructor or the init() function was called from.
then call repaint() function or something.

Android game engine design: how to synchronize game loop and canvas updating thread?

I wanted to rewrite my simple game engine to run on Android and I am wondering how can I synchronize two running threads. Right now I have the following:
Runner is the main activity, entry point for this game;
CanvasView is just a canvas on which drawing is being made;
GameWorld is - as the name suggests - class which stores the current information about the state of the game. For now, lets just say that it also contains a Level.
GameLoop is a separate thread which is updating the game state;
CanvasThread is a separate thread, which is being run to draw the current Level on CanvasView.
As the level is just a simple array, CanvasThread just iterates through the array and draws it on screen. And I have few questions regarding this:
is there a possibility to run the onDraw() method of CanvasThread on demand? In current state of the engine it is just being relaunched when the execution of previous one is finished.
I want to implement some kind of three way handshake between GameLoop and CanvasThread, something similar to:
GameLoop -> CanvasThread: please stop updating
Canvas -> GameLoop: ok, stopped
GameLoop -> CanvasThread: ok, you may resume.
What is the best way to do so? I am a total Java / Android newbie so my way of setting the engine is most probably not the best / optimal one. If you have any suggestions to the design, I will gladly appreciate them.
Thank you.
PS: If I had violated all best practices while creating the diagram above, please forgive me.
Android has an easy way to handle thread communication. You can use a Looper and a Handler to send messages, or complete Runnables, between the Threads.
Look at Android Guts: Intro to Loopers and Handlers on mindtherobot.com for an introduction.
You can send an "empty" message to signal something, or supply some arguments. You can send the message immediately, or with some delay.
If you design your game loop by sending messages to itself, it would be easy to inject messages from other threads.
What I created long long time ago. Maybe it helps a little
http://code.google.com/p/candroidengine/
I believe you'll find it a lot easier if they don't communicate.
Instead, put a couple constraints on to keep yourself sane:
Make a very tight game loop. If you're going to be updating your canvas at, let's say, 30 fps (about 33 ms) make your game loop take no longer than 10 or 20 ms.
Put a lock on your game loop and canvas update. Now, each one will wait for the other to finish before doing their thing. You won't end up with a canvas that has the half the screen representing before the loop and the other half of the screen after the loop.
Example:
class GameLoop extends Thread {
public void run() {
while(true) {
synchronized(theGameWorldObject) {
// update game info here
}
}
}
}
class Canvas {
updateCanvas() { // or whatever you call it
synchronized(theGameWorldObject) {
// update canvas here
}
}
}

Categories

Resources