Proper multitasking for android - java

Hi im developing an android application and im wondering how i make the app use less CPU while backgrounded. For example, my application pauses once it loses focus but the cpu usage is still 50%
Edit
while (!pause) {
Canvas c = null;
try {
c = sHolder.lockCanvas(null);
synchronized (sHolder) {
doDraw(c);
powerUps();
}
} finally {
if (c != null) {
sHolder.unlockCanvasAndPost(c);
}
}
}
Then when you pause and resume it just changes the pause variable

IMO, you should not be looping at all while your app is paused.
See this page for more details about the "proper" lifecycle of an android app.
Also note that with any busy loop design your app will be using 100% of the CPU - I'm not sure if starting a loop from the onResume() method is correct; my instinct is to have each iteration of your loop performed by a separate call initiated by a call to Handler.post(), with the last statement re-posting the next call. Otherwise, the application's main thread will be starved, right?
Maybe something like this:
void iterate() {
Canvas c = null;
try {
c = sHolder.lockCanvas(null);
synchronized (sHolder) {
doDraw(c);
powerUps();
}
} finally {
if (c != null) {
sHolder.unlockCanvasAndPost(c);
}
}
this.handler.post(this.iterateRunnable);
}
void onResume() {
this.handler = new Handler();
this.iterateRunnable = new Runnable() {
#Override public void run() { iterate(); }
};
this.handler.post(this.iterateRunnable);
}

Related

ConcurrentModificationException when updating sprite images

I keep getting a ConcurrentModificationException when running my game which utilizes multithreading to create new sprites and move them. The main problem appears to happen with the creation and/or movement of "Fireballs".
I've been able to run my program successfully with no exceptions appearing by commenting out the createNewFireballs method. However, whenever I do utilize the createNewFireballs method, the error commonly appears whenever I call a function that updates the image of the Fireball Sprite (and doesn't ever happen for any other type of sprite.) I was wondering if anyone could help me locate the source of my problem and potentially solve the issue.
public synchronized void createNewFireball() {
new Thread(new Runnable() {
public void run() {
while (gameNotPaused && hero.isNotDead()) {
fireball = new Fireball(dragon.getX(), dragon.getY());
fireballs.add(fireball);
try
{
Thread.sleep(100); //Waits for .1 second
}
catch(InterruptedException e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}).start();
}
//The problem commonly occurs in the update method,
//specifically the line "FireballIter.next().updateImage(g);"
public synchronized void update(Graphics g) {
Iterator<Sprite> FireballIter = fireballs.iterator();
Iterator<Sprite> arrowIter = arrows.iterator();
while (arrowIter.hasNext()) {
arrowIter.next().updateImage(g);
}
Iterator<Sprite> iterator = sprites.iterator();
while (iterator.hasNext()) {
iterator.next().updateImage(g);
}
while (FireballIter.hasNext()) {
FireballIter.next().updateImage(g);
}
}
//Although sometimes it occurs as a result of updateScene, which is
//called in another method which moves all the "projectile" sprites
public synchronized void updateScene(int width, int height) {
Iterator<Sprite> arrowIter = arrows.iterator();
while(arrowIter.hasNext()) {
Sprite spriteObject = arrowIter.next();
((Arrow) spriteObject).updateState();
if (spriteObject.overlaps(dragon, 350, 350)) {
dragon.arrowHit();
System.out.printf("Dragon was hit at %d, %d%n, while arrow was at %d,%d%n", dragon.getX(), dragon.getY(), spriteObject.getX(), spriteObject.getY());
arrowIter.remove();
}
}
Iterator<Sprite> fireballIter = fireballs.iterator();
while(fireballIter.hasNext()) {
Sprite spriteObject = fireballIter.next();
((Fireball) spriteObject).updateState();
}
}
#Override
public synchronized void run() {
while (model.getGameNotPaused()) {
model.updateScene(view.getWidth(), view.getHeight());
view.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
JOptionPane.showMessageDialog(null, "Press R to resume game.");
}
}
}
Making createNewFireball synchronized does nothing useful: the synchronization only applies to the execution of that method, not the runnable executed by the thread (which is good, because otherwise none of the other methods would be able to execute until the while loop finished).
Put the fireballs.add into a synchronized block, taking care to ensure you are synchronizing on the right thing:
If you simply use synchronized (this), you would be synchronizing on the Runnable.
Instead, use synchronized (TheContainingClass.this) (where TheContainingClass is the name of the class containing these methods).
Assuming your fireballs is an ArrayList<Fireball>, you could also consider switching it to CopyOnWriteArrayList , a thread-safe variant of ArrayList

How do I reach the running instance of my Thread?

Basically, I have a class called Playback which extends a thread. I want to be able to run functions i have defined from this class from my thread object, but when i do they have no affect on the current thread of said object. I can only get my functions to work when called if i was .run() instead of .start() but that causes my GUI to freeze up. Here is my code
Playback function = new Playback(list, progBar, settings);
function.start();
function.terminate();
The above code does not work but the below does
Playback function = new Playback(list, progBar, settings);
function.run()
function.terminate();
When i use run though it causes my GUI to freeze. How do i call my methods on a already running thread?
here is my playback class:
package chronos.Functions;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.util.List;
import javafx.scene.control.ProgressBar;
import chronos.Graphics.InputValue;
public class Playback extends Thread {
List<InputValue> list;
ProgressBar progBar;
Settings settings;
boolean terminated = false;
public Playback(List<InputValue> list, ProgressBar progBar, Settings settings) {
this.list = list;
this.progBar = progBar;
this.settings = settings;
}
public void run() {
try {
Robot bot = new Robot();
double x = settings.getCycleNumbers();
Thread.sleep(settings.initialDelay);
for (double c = 0; c <= x; c++) {
if (terminated == false) {
System.out.println(terminated);
System.out.println(isInterrupted());
progBar.setProgress(c/x);
if (list.isEmpty() != true) {
for (InputValue i: list) {
if (terminated == false) {
if (i.getType() == "key") {
long longRuntime = System.currentTimeMillis();
if (settings.recDurations == true) {
if (i.getDuration() > 0) {
while(i.getDuration() > System.currentTimeMillis() - longRuntime ) {
bot.keyPress(i.getCode());
}
} else {
bot.keyPress(i.getCode());
}
} else {
if (settings.getDurationTime() > 0) {
while(settings.getDurationTime() > System.currentTimeMillis() - longRuntime ) {
bot.keyPress(i.getCode());
}
} else {
bot.keyPress(i.getCode());
}
}
} else {
bot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
if (settings.recDurations == true) {
Thread.sleep(i.getDuration());
} else {
Thread.sleep(settings.getDurationTime());
}
bot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
if (settings.recPositions == true) {
bot.mouseMove(i.getX(), i.getY());
}
}
if (settings.trackDelay == true) {
Thread.sleep(i.getDelay());
} else {
Thread.sleep(settings.getKeyDelay());
}
} else {
break;
}
Thread.sleep(settings.cycleDelay);
}
} else {
progBar.setProgress(0);
}
} else {
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void terminate() {
System.out.println("terminated");
terminated = true;
}
}
How do i call my methods on a already running thread?
You can't.
A thread does what its run() method does. There is no way to change that. If you want a thread to do a certain thing, then you must create it with a run() method that does that thing.
Bear in mind, that there is no limit to what the run() method can do. For example, it might wait on a BlockingQueue, for "command" objects, and each time it gets a command, it might "perform" the command. I that case the run() method could do as many "different things" as you have different command objects that you can pass to it.
Your thread doesn't terminate because you don't properly synchronize access to the terminate variable: one thread modifies it, and the other one reads it.
If it's not at least volatile, the Java memory model doesn't guarantee that the modification made by one thread is visible from the other one.
So, either declare your variable volatile, or use an AtomicBoolean, or use the native mechanism allowing to interrupt threads: call thread.interrupt() to ask it to stop, and check for Thread.currentThread().isInterrupted() in the loop to check if the thread must stop.
The advantage of using interrupt is that the thread won't wait for sleep() to return before being able to stop. Instead, sleep() (and other blocking methods) will immediately throw an InterruptedException, signalling you that the thread has been asked to stop.

Java code speed improvement

Hi all may such a code cause lag of process?
while(true)
if(!connected) break;
As we see it checks for condition all the time. Would it be faster if I set small sleep in each iteration.
The code runs on Android GingerBread.
EDIT:
It waits for other Thread to finish and set variable Connected to false. Variable connected is used like lock. thread usually finds it true and waits to be false. then sets to true and only changes it at the end.
I think it would be better to add small sleep in your loop, to free processor resources for other processes, especially on one-core processor.
I belive it could be like this:
while(connected) {
// do stuff...
Try something like this:
private Integer connected;
private ConnectedListener connectedListener;
public interface ConnectedListener {
public void onDisconnected();
}
private void startThreads() {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (connected) {
connected++;
}
// do some random long work
synchronized (connected) {
connected--;
if (connected == 0 && connectedListener != null) {
//let the listener know that we are completely disconnected
connectedListener.onDisconnected();
}
}
}
}).start();
}
}

IllegalArgumentException in unlockCanvasAndPost (android live wallpaper)

I've created my first live wallpaper implementing drawing in a separate thread. So now I have a WallpaperService and my WallpaperPainter who does the job. The problem is that I getting a IllegalArgumentException in unlockCanvasAndPost method on some of devices (Samsung Note is the one). I've read all recomendations I could find but couldn't fix that bug. Seems like the unlockCanvasAndPost is called when surface is destroyed so canvas is invalid. Here is the essential parts of code:
In wallpaper service:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
super.onSurfaceChanged(holder, format, width, height);
painting.setSurfaceSize(width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
painting.start();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
painting.stopPainting();
while (retry) {
try {
painting.join();
retry = false;
} catch (InterruptedException e) { }
}
super.onSurfaceDestroyed(holder);
}
In the painting thread:
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
public void run() {
this.run = true;
Canvas c = null;
while (run) {
try {
synchronized (this) {
Thread.sleep(50);
c = this.surfaceHolder.lockCanvas();
doDraw(c);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
}
}
// if pause...
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) { }
}
}
}
}
Can anyone give me any clue what I'm doing wrong? I'm new both for Java and Android.
If error is: UnlockAndPost Failed, it means it unlocked no buffer.
After this.surfaceHolder.unlockCanvasAndPost(c);
you can append
this.surfaceHolder.lockCanvas();
(sorry for my poor English proficiency)
When you open the preview of wallpaper, creates the object WallpaperService and further creates an instance of Engine. Then the stream starts drawing wallpaper.
Then, when you click "Set wallpaper" - a new instance of WallpaperService is not created. But he call the onCreateEngine() method, which returns another (second) instance of Engine. Which also runs its own thread.
Now you have two competing thread!!! So they lead to an exception being thrown.
All you need to do to fix the bug - is to write a correct method onCreateEngine().
replace this:
#Override
public Engine onCreateEngine() {
return new SampleEngine();
}
to this:
private SampleEngine engine;
#Override
public Engine onCreateEngine() {
if (engine!=null) {
engine.painting.stopPainting();
engine = null;
}
engine = new SampleEngine();
return engine;
}
I don't see a definitive problem but here are some thoughts.
There is a chance that you unlock a canvas that has not been locked. I would set c = null; at the top of your while loop otherwise the previous value of c would be unlocked the next time through the loop.
while (run) {
Canvas c = null;
...
Your run field should be marked as volatile because it is accessed by multiple threads.
Never call Thread.sleep(...) inside of a synchronized block. That's a very bad practice since it blocks other threads unnecessarily.
Make sure you at least log your exceptions. Be extremely careful about catch (Exception e) {}. All that does is mask your problems.
There isn't much point in doing the join() inside a while loop. If your thread gets interrupted you should interrupt the painting thread and quit.
Since you are both sleeping and waiting, it would make more sense to remove the sleep and do something like:
try {
synchronized (this) {
if (wait) {
wait();
else {
wait(50);
}
}
} catch (Exception e) {
e.printStackTrace();
}
I had the same problem with my live wallpaper. On a Nexus 5 emulator it runs fine, but when I run it on a Nexus 10 emulator it crashes the moment the app loads.
I found out that the problem was because the default Skin for the emulator has the wrong resolution. After I changed the Skin to "No Skin" then I don't get the crash anymore.
For more information on how to fix the Skin with wrong resolution, please see:
Android Studio - Tablet emulator not showing correct resolution

Setting up the correct multi threading

Unfortunately I have a pretty bad understanding of how to properly set up threading. I know there is a bunch of info on this both here on SO.SE and on other sites but I can't seem to relate what I read correctly to what I'm doing.
My problem is that I have a method that takes two parameters where one is divided by the other. The quotient (result) is used to fill up a visual progress bar. When the quotient gets to 1, (readBytes/contentLength == 1), I want some thread (I guess) to wait for a given time before the progress bar is removed from the layout. I know all the code needed to set the value to the progress bar and how to remove it from the view, my question is how do I make it wait for, say, 2000 ms before the action is triggered to remove the component?
This is probably basic threading knowledge but I'm having huge problems with it.
So far I've tried these two approaches:
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
synchronized (this) {
while(readBytes/contentLength != 1) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
fileListItem.removeProgressIndicator();
}
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
AND
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(readBytes/contentLength == 1) {
Thread t = new Thread();
t.start();
try {
t.wait(2000);
fileListItem.removeProgressIndicator();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
} else {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
With no success. In the first example the main thread seems to be the one waiting and nothing happens. And in the second example I get an exception on the t.wait(2000);. I'm at a loss of how I should do..
EDIT: With the input from Bohemian I got it working.
#Override
public void updateProgress(final long readBytes, final long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(!threadIsRunning) {
new Thread(new Runnable() {
#Override
public void run() {
threadIsRunning = true;
while(!fileIsAdded) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
LOGGER.error(e.getMessage());
break;
}
}
fileListItem.removeProgressIndicator();
threadIsRunning = false;
}
}).start();
}
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
if(readBytes == contentLength)
fileIsAdded = true;
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
It still needs some tidying up but the basics are now working!
In all probability SwingWorker is the right tool for your task. There is a full code sample in the Javadoc. Notice the method setProgress -- that's ideal to update your progress bar.
If all you need is really just a fixed 2 second delay for clearing the progress bar, then you want to use a Swing Timer. It doesn't even involve multithreading, you just write a callback handler that will be executed after the specified delay.
I wouldn't have the main thread wait. It's bad practice because it isn't scalable and makes your GUI jittery.
Instead, I would pass a timeout value and a couple of callbacks to the worker thread to execute when it exceeds its timeout/completes its work. That way the main thread is free to go back to doing whatever it wants to.
Just for illustration purposes, your "completion" callback might look like:
new Runnable() {
public void run() {
// code that hides the progress bar
}
}
Your "timeout" callback might look like:
new Runnable() {
public void run() {
// code that displays an error message
}
}
By the way, to get a thread to do something, you also pass it a Runnable:
new Thread(new Runnable() {
public void run() {
// code that runs when your thread starts
}
}).start();
I think what you really need is
Thread.sleep(2000);
instead of wait. While wait can be used for sleeping, its primary function is for inter-thread signaling and requires a lock on the object being waited on, which you have not acquired, hence the exception.
Edit: Upon further inspection I notice that you are not doing things correctly. You are just creating a thread with no associated run method:
Thread t = new Thread();
t.start();
Hence your thread is not executing anything.
I suggest reading a Java threading tutorial on how to set up threads correctly: http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html

Categories