From single thread to multi thread android studio - java

I am making space invaders game. This is main acitivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// Get a Display object to access screen details
Display display = getWindowManager().getDefaultDisplay();
// Load the resolution into a Point object
Point size = new Point();
display.getSize(size);
spaceInvadersEngine = new SpaceInvadersEngine(this, size.x, size.y);
setContentView(spaceInvadersEngine);
}
// This method executes when the player starts the game
#Override
protected void onResume() {
super.onResume();
// Tell the gameView resume method to execute
spaceInvadersEngine.resume();
}
// This method executes when the player quits the game
#Override
protected void onPause() {
super.onPause();
// Tell the gameView pause method to execute
spaceInvadersEngine.pause();
}
Class SpaceInvadersEngine has two main functions update() where all calculation is done and draw() where I draw all elements. After adding more elements game works but it is slow, so I decided to separate it in more threads.
This is my code in SpaceInvadersEngine
public void resume() {
playing = true;
gameThread = new Thread(runnable);
gameThread.start();
drawThread = new Thread(this);
drawThread.start();
}
In gameThread runnable I have
while(playing){update();}
and for drawThread in run() i have only draw();
While game load and prepare for new level (create new invader and upgrade objects) it takes up to 5 seconds and game freeze. How to remove that waiting time? When I try drawThread with runnabletoo, it does not draw anything.
Also, for some reason, when I do with two threads, my shipsometimes random blink as a big image in one frame, and then returns to normal, it was not blinking in single thread?

I would suggest you using Kotlin language with coroutines for asynchronous code. It's not hard to start using and it can really improve overall performance and code readability.
fun exampleMethod() {
// Starts a new coroutine on Dispatchers.Main as it's the scope's default
val job1 = scope.launch {
// New coroutine with CoroutineName = "coroutine" (default)
}
// Starts a new coroutine on Dispatchers.Default
val job2 = scope.launch(Dispatchers.Default + "BackgroundCoroutine") {
// New coroutine with CoroutineName = "BackgroundCoroutine" (overridden)
}
}
If you are open to change technology a bit, look at this and try coroutines. It's a fresh and great way how to deal with long-running tasks on Android. Also, you can find many articles and examples for them.
Improve app performance with Kotlin coroutines

Related

JavaFX AnimationTimer not stopping properly

So, I am creating the snake game using JavaFX and I cannot seem to make the game pause properly, i.e. it pauses occasionally and other times, the game just ignores the pause. So, basically I have a Main class where I initialize all the GUI components, and it also acts as the controller for the javafx Application.
I have a Button named gameControl which starts/pauses the game, a variable Boolean pause which keeps track of the game states (new/paused/running), and the methods startGame, pauseGame.
The gameControl button's EventHandler is as follows:
gameControl.setOnClicked(event->{
if(paused == null) startGame(); //new game
else if(paused) continueGame(); //for paused game
else pauseGame(); //for running game
});
The startGame function looks something like this:
void startGame(){
paused = false;
Snake snake = new Snake(); //the snake sprite
//following gameLoop controls the animation of the snake
gameLoop = new AnimationTimer(){
#Override
public void handle(long now){
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
//following code is for slowing down the gameLoop renders to make it easier to play
Task<Void> sleeper = new Task<>(){
#Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
gameLoop.start();
return null;
}
};
new Thread(sleeper).start();
//force garbage collection or else throws a bunch of exceptions after a while of running.
//not sure of the cause...
System.gc();
}
};
gameLoop.start();
}
AnimationTimer gameLoop are variables of the class to allow calling from other functions.
And the pauseGame function:
void pauseGame() {
paused = true;
gameLoop.stop();
}
So, as I have said before the game doesn't pause everytime I hit the gameControl button, and I suspect it is due to the Thread.sleep(30); line inside the Task of the gameLoop. That being said, I am still not fully sure and have no idea how to fix this. Any help would be appreciated.
What type is 'paused' ? You check it for null, but then treat it as a boolean.. I can't understand why it would be a big 'B' Boolean object wrapper instead of the primitive boolean type.
This:
//following code is for slowing down the gameLoop renders to make it easier to play
Task<Void> sleeper = new Task<>(){
#Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
gameLoop.start();
return null;
}
};
Is an absolutely horrible way to throttle the speed. Let your game loop run, check the time on each loop to see if enough time has elapsed that you should update things. Your animation timer will drive the game. You don't want to pause the main platform thread, you don't want to pause any worker threads that are handling tasks. If you are scheduling tasks have them scheduled to run at the intervals that you want - don't throttle the thread in the call() method.
What you really want is something like this:
//following gameLoop controls the animation of the snake
gameLoop = new AnimationTimer(){
#Override
public void handle(long now){
if ((now - lastTime) > updateIterval) {
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
lastTime = now;
}
You could even make that a loop to "catch up" in case the Animation timer fell behind for some reason:
while ((now - lastTime) > updateIterval) {
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
lastTime += updateIterval;
}
Your intuition that Thread.sleep(30); may be causing an issue is on the right track. A user may click the button calling pauseGame, setting paused to true, and telling the gameloop to stop. If the new sleeper thread is started and sleeping at that moment it will call start() on the gameloop when it wakes up.
One option may be to simply check the value of paused in the sleeper task to determine if it should start the gameloop.
Task<Void> sleeper = new Task<>(){
#Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
if (!paused) {
gameLoop.start();
}
return null;
}
};
Given that the paused value is being set and read from multiple threads, I would recommend adding a mechanism to ensure you don't get non-deterministic behavior. Swapping the Boolean to an AtomicBoolean is a straight forward option for ensuring consistency.

How can I pause/continue scheduled task?

I'm new to JAVA and trying to learn some concurrency concepts.
I have a simple GUI class that pops-up a window with 1 button which I want to use for pause/continue.
Also, I have a class that extends TimerTask, it looks like below and start with the GUI:
public class process extends TimerTask {
public void run() {
while(true) { /*some repetitive macro commands.. */ }
}
}
Real question is, how can I pause the task onClick of the button and also continue onClick of the button if already paused?
I have taken a step to use a boolean to flag the button as it changes from pause to continue on each click.
But then I had to type a lot of while(button); for busy waiting inside the while()...
Do you think I can make like Thread.sleep() or something but from outside the task thread?
OLD ANSWER
Basically, there is no support for pause and resume on TimerTask, you can only cancel, check here
perhaps you might want to read about threading as that's the alternative I know of that has an interrupt and start features and then you can keep track of the progress of what you're doing to resume where it stopped.
So, I will suggest you go through this link, because you need to understand threading not just copy a code to use, there is a sample code there that will definitely solve your problem also.
Note that running an endless while loop will basically cause your program not to respond, unless the system crashes. At a certain point, the data becomes an overload and the program will overflow. This means it will fail.
.
NEW ANSWER
So, response to the new question, I was able to run a tiny little program to demonstrate how you can achieve something that looks like multithreading when working with SWING.
To rephrase your question: You want to run an indefinite task like let say we're playing a song, and then onclick of a button to pause the song, on click again should continue the song?, if so, I think below tiny program might work for you.
public class Test{
static JLabel label;
static int i = 0;
static JButton action;
static boolean x = false; //setting our x to false initialy
public static void main(String[] args) {
JFrame f=new JFrame();//creating instance of JFrame
label = new JLabel("0 Sec"); //initialized with a text
label.setBounds(130,200,100, 40);//x axis, y axis, width, height
action=new JButton("Play");//initialized with a text
action.setBounds(130,100,100, 40);//x axis, y axis, width, height
f.add(action);//adding button in JFrame
f.add(label);
action.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if(x){
x = false; //Update x here
action.setText("Play");
action.revalidate();
}else{
x = true; //Update x here also
action.setText("Pause");
action.revalidate();
if(x){ //Using x here to determind whether we should start our child thread or not.
(new Thread(new Child())).start();
}
}
}
});
f.setSize(500, 700);//500 width and 700 height
f.setLayout(null);//using no layout managers
f.setVisible(true);//making the frame visible
}
}
class Child implements Runnable{
#Override
public void run() {
while (x) {
//You can put your long task here.
i++;
label.setText(i+" Secs");
label.revalidate();
try {
sleep(1000); //Sleeping time for our baby thread ..lol
} catch (InterruptedException ex) {
Logger.getLogger("No Foo");
}
}
}
}

How to pass GL10 object inside of run() method

I believe the problem I have is that gameThread won't work unless I have use GL10 gl in gameview.drawFrame(). I've tried creating a Object gl passing that in but still wont work. Also is it wrong to use game.onResume to update the game?
I've created an instance of the gameThread inside of Main.class and classed the
public class GameThread extends Thread {
Object gl;
private static int MAX_FRAME_SKIPS;
private static int FRAME_PERIOD;
private OpenGLActivity game;
private MyGLRenderer gameView;
private boolean gameRunning = true;
private boolean running = false;
Handler handler = new Handler();
public GameThread( int maxFPS, int maxFrameSkips) {
game = new OpenGLActivity();
gameView = new MyGLRenderer();
MAX_FRAME_SKIPS = maxFrameSkips;
FRAME_PERIOD = 1000 / maxFPS;
gl = new Object();
}
#Override
public void run() {
long beginTime;
long timeDiff;
int sleepTime;
int framesSkipped;
beginTime = System.currentTimeMillis();
framesSkipped = 0;
this.gameRunning = this.game.isRunning();
this.game.onResume(); // Update game
this.gameView.onDrawFrame((GL10) gl); // Render the game
timeDiff = System.currentTimeMillis() - beginTime; // Calculate cycle length
sleepTime = (int) (FRAME_PERIOD - timeDiff); // Calculate time available to sleep
// Checks if got time to sleep, either sleeps thread or catches up
if (sleepTime > 0) {
if (this.gameRunning && running) {
handler.postDelayed(this, sleepTime);
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
this.game.onResume(); // Update without rendering
sleepTime += FRAME_PERIOD; // Add frame period to check if in next frame
framesSkipped++;
if (this.gameRunning && running) {
this.run(); // No time to wait! RUN! CATCH UP!
}
}
}
}
public void setRunning(boolean running) {
this.running = running;
}
}
public class Main extends Activity{
GameThread gt = new GameThread(48, 100);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
public void PlayGame(View v) {
Intent intent = new Intent(Main.this, OpenGLActivity.class);
startActivity(intent);
gt.setRunning(true);
}
The fact that you don't have a GL10 object is only a symptom here. In fact, I don't think that's ever used on Android. It's part of the javax.microedition.khronos.opengles package, which I figure is some kind of standard Java OpenGL ES interface. I'm not sure if it's functional, but I certainly have never seen anybody use it.
The OpenGL interfaces that are normally used in Android are in the android.opengl package, and are named GLES10, GLES11, GLES20, GLES30, GLES31.
On those classes, all the methods are static. So you never really need an object instance to make OpenGL calls.
But, and this is your actual problem: To make OpenGL calls, you need to create an OpenGL context, and make it current. You will also need a rendering surface. There are two main options for this:
The (moderately) hard way by using the EGL14 interface (or EGL10 if you need to support API levels lower than 17).
You can go the more convenient and widely used route, and use a GLSurfaceView, which creates the context and rendering surface for you.
I recommend that you start with the official tutorial in the Android documentation. All of the above will become much clearer once you go through this: http://developer.android.com/training/graphics/opengl/index.html.
You should also be aware that OpenGL ES 1.x is mostly considered obsolete. ES 2.0 and higher versions are much more widely used these days.

How to cycle through background colors in Android / Java?

I have a list of hex colors with a duration in milliseconds for each one. I would like to fill the screen with each color for its duration, then move on to the next color.
I tried to iterate over the colors to do the following:
myView.setBackgroundColor(Color.parseColor( theColor ));
SystemClock.sleep( theDuration );
myView.setBackgroundColor(Color.parseColor( nextColor ));
SystemClock.sleep( nextDuration );
etc...
which seemed obvious to me but doesn't do anything to the view when it's running, at least in my AVD. I'm learning that it's because Android only draws at predefined times. (I tried calling "Invalidate()" as well with no luck.)
What is the best way to display all the colors consecutively?
(I realize I shouldn't be calling sleep() either, so any suggestions for that would also be appreciated.)
Thanks.
new Thread() {
#Override
public void run() {
YourActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myView.setBackgroundColor(Color.parseColor( theColor ));
}
Thread.sleep( theDuration);
YourActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myView.setBackgroundColor(Color.parseColor( nextColor ));
}
Thread.sleep( nextDuration );
}
}.start();
Put this in a method and call it.
There are many ways to achieve what you want. One could be to use Handler and Runnable. Assuming you know how to get current color and duration, you could do:
declare Runnable as class variable
private Runnable runnable = null;
inside onCreate(), after you set initial view, initialise Handler
final Handler handler = new Handler();
initialise runnable and change the background in run() method
runnable = new Runnable() {
#Override
public void run() {
//change the color
myView.setBackgroundColor(currentColor);
//run it again in nextDuration miliseconds
handler.postDelayed(toggle, nextDuration);
}
};
//start runnable in theDuration miliseconds
handler.postDelayed(toggle, theDuration);
You could have arrays of colors and durations and cycle through them with index variable. This is assuming that myView is a valid view.
EDIT:
To those who downvoted, read the documentation for Handler:
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it...
In other words, you are creating a handler in onCreate() of your activity, so it will be able to update your view.
This blogpost from adroid-developers website uses very similar construct as proposed above.
The Handler runs the update code as a part of your main thread, avoiding the overhead of a second thread and also making for easy access to the View hierarchy used for the user interface.
See here and here answered by CommonsWare and here - answered by Laith Alnagem.
I ended up creating a Runnable inside the my button click event handler. Everything (looping through the colors and durations plus "sleeping" based on the durations) is done in the Runnable run() method.
public void playOnClick(View v) {
Runnable runnable = new Runnable() {
public void run() {
...
}
Then I created a handler inside my UI Activity class that just changes the color of the background.
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
String theColor = b.getString("color");
myView = (View) findViewById(R.id.bigView);
myView.setBackgroundColor(Color.parseColor(theColor));
}
};
Inside the run() method, he Runnable sends a message to the handler containing the background color using Bundle/Message objects:
b = new Bundle();
b.putString("color", theColor);
msg = new Message();
msg.setData(b);
handler.sendMessage(msg);

Using a counter inside a java.util.Timer in Android Activity causes app to crash

I'd like to accomplish something which I would think to be simple, but is turning out to be a hassle.
I have a loading screen with a picture, and I'd like for it to fade in and out as the application is loading. I decided to accomplish this by changing it's opacity frequently relative to the sine value of a counter. My code is as follows:
ImageView loadingRaven; //loading raven at the start of the app
Timer timer; //timer that we're gonna have to use
int elapsed = 0; //elapsed time so far
/*
* the following is in the onCreate() method after the ContentView has been set
*/
loadingRaven = (ImageView)findViewById(R.id.imageView1);
//fade the raven in and out
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
//this line causes the app to fail
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2);
}
};
timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 50);
What is the problem that's causing my program to fail? Am I correctly using Timer and TimerTask? Or is there perhaps a better way to update the opacity of the image frequently so it eases in and out smoothly?
Thanks
TimerTask runs on a different thread. So update ui on the main ui thread. Use runonuithread
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2)
}
});
}
};
TimerTask runs on a different thread. You can use Handler and postDelayed as suggested by
pskink

Categories

Resources