I'm working on a Tetris-app and I have a Thread.sleep command to animate the falling of the tetriminos. But that creates a conflict with the UI. So I tried runOnUiThread() like this:
while (gameover == false) {
tetriminoSettled = false;
try {
Thread.sleep(1000 - (counter * 3));
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
Random ran = new Random();
int x = ran.nextInt(7) + 1;
addTetrimino(createTetrimino(x)); //the UI operation
gridView.invalidate();
}
});
But the UI gets only updated after the game ends.
Do you think AsyncTask is a good approach?
Please try to keep in mind that I later need additional UI-Threads for shifting the tetriminos left and right and so on.
Thanks!
Judging from the code you posted, it looks like you are using a gridview for a game. It is possible but not worth the effort. Just use a SurfaceView as shown in this short tutorial. You'll have an onDraw callback in which you can update whatever you like every drawing cycle. Have fun, coding games is really hard :).
Try gridView.postInvalidate();
Related
I'm having trouble with making views visible. As in: they do all appear, but at the same time, whereas I would like to show them with some delay in between. Currently I have the following code, which should make it more clear:
public void performExperiment (View v) {
Log.i(TAG, "Experiment has started on view: " + v);
final ArrayList<FocusPoint> permutation = new ArrayList<>(Arrays.asList(focusPoints));
Collections.shuffle(permutation);
for (FocusPoint fp: permutation) {
try {
Thread.sleep(1000);
fp.setVisibility(ImageView.VISIBLE);
//fp.invalidate();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Sleep failed");
}
}
}
The FocusPoint-class is an extension of ImageView in Android and the method is called upon a button-click.
What needs to happen is that all the views show up in a random order on the screen, with a second between them. This code however waits for 16 seconds (the amount of views is 16) and then shows all the views at once. I tried invalidating my the view to redraw it, and I also tried to take 'fp.setVisibility(ImageView.VISIBLE)' out of the try-catch block, but both didn't work. (Of which the latter obviously doesn't work, I didn't really expect that to work, but I'm getting really desperate :P) I have been searching for hours now, and none of the StackOverflow-pages and other fora/documentation had an answer for this problem. How can I make sure that the focuspoint draws, before the loop continues to the next?
Using Thread.sleep(ms) to delay the UI thread is a very dangerous idea, and as you can see, it doesn't lead anywhere. By blocking the thread for 16 seconds, you are effectively freezing the application for that period - including any redraws and other event handling that might happen during that time. Don't ever do that.
Instead, use a Handler and its postDelayed(Runnable, ms) method to schedule visibility changes in the future. Handlers work by adding messages to the event loop, so they don't disrupt normal behavior.
Check this modified version of your code:
private static final long FP_SHOW_DELAY_MS = 1000;
private Handler handler = new Handler();
public void performExperiment (View v) {
Log.i(TAG, "Experiment has started on view: " + v);
final ArrayList<FocusPoint> permutation = new ArrayList<>(Arrays.asList(focusPoints));
Collections.shuffle(permutation);
for (int i = 0; i < permutation.size(); i++) {
final FocusPoint fp = permutation.get(i);
handler.postDelayed(new Runnable() {
#Override
public void run() {
fp.setVisibility(View.VISIBLE);
}
}, (i + 1) * FP_SHOW_DELAY_MS);
}
}
In a sort-of-working application I see this monstrous code:
class SomeUglyClass extends Thread {
ArrayList<SomeData> someDataStructure = new ArrayList<SomeData>();
Handler mHandler = new Handler() {
// a lot
// writing to someDataStructure
}
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
} // end of run(), total 500 lines of code
} // end of SomeUglyClass, total 4K lines of code
Maybe you already see the problems with this code. If not, here they are:
mHandler is attached to the UI thread (because it is created by the thread that loads the class, which is the main thread)
there's no looper (which is fact is the bug)
the thread wastes CPU time and drains the battery
someDataStructure is not thread-safe, but synchronizing elementary access operations will not help; synchronizing large blocks of code in a endless loop will likely block the guarded resource and make it unavailable for other threads; finally, it is not only someDataStructure, the whole class is based on the assumption that only one thread can run its code.
I cannot just add the looper, because the endless loop in run() has to be run, while Looper.loop(); also is an infinite loop. One thread cannot run two infinite loops.
Despite this epic architectural fail, the code is really doing something, it cannot be re-written at once, it is 4K lines of code, and often I can only guess what the code really does.
I need to refactor it. It should be a sequence of small steps preserving the functionality.
How do I refactor this terrific code?
You should try separation of concerns: try first to divide the whole class into many smallest one, each one responsible for doing/dealing with exactly one thing.
You may have something for data Access (read/write data), service (isolated business logic), and the UI. You may use event bus to decouple between objects (consider otto) and may be dependency injection (consider Dagger).
This process of separation will help you understand what each piece of code is doing and also the dependencies between the different parts, thus making writing unit/integration tests much easier.
Add lots of tests, use version control and then work as slowly as you need to.
The 1st step has been to change:
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
}
to:
#Override
public void run() {
Looper.prepare();
mHandler = new MyHandler();
mHandler.post(run_step);
Looper.loop();
}
Runnable run_step = new Runnable() {
int some_count, ...;
#Override
public void run()
{
//while(true) {
// a lot
// r/w access to someDataStructure
mIntoThreadHandler.postDelayed(this, 1);
//}
}
}
This preserves the functionality but still wastes CPU time. The urgent bug has been fixed, and the issue has been closed; I could not sell "must refactor to kill monstrous code" to my management, but I could sell "this can work faster if I refactor," so a new separate issue has been opened. UGH!
PS no chance to sell "lots of tests".
I have looked into other camera flashlight related problems in stackoverflow, but couldn't find an answer that solves my issue. The flashlight flashes for 6-8 times and then the app crashes. Here I have a blink() method that calls cameraon() and cameraoff() in a loop. Could you please let me know where I went wrong?
My code can be found here: http://pastebin.com/3LRMwd1J
The logcat output can be see here: http://pastebin.com/2GTpn8Ux
I have tried using surface textures, tried to include Thread.sleep() in betweencameraon() and cameraoff() but so far no luck.
I use Android 4.4 with latest sdk and jdk versions.
I use nexus 5 for testing.
Thanks in advance!
just take Thread in Blink() method and put your code with if else
boolean tourchon=false;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
if(tourchon){
cameraoff();
tourchon=false;
}else{
cameraon();
tourchon=true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
Try this code...
Separate the obtaining of camera object from your cameraOn() method, as i understand this method should be turning the flash on, calling open() that many times in that short time may be causing your problems as this documentation suggests.
Caution: On some devices, this method may take a long time to complete. It is best to call this method from a worker thread (possibly using AsyncTask) to avoid blocking the main application UI thread.
So have your on and off methods just change the flash mode, because you already have the camera instance.
See if my code helps any:
https://github.com/wolfhorse/SimpleFlashlight
It doesn't blink but it may be a good reference for you.
EDIT:
I modified the onClick() event of the toggle button in the SimpleFlashlight app referenced above by adding the code below and it blinks/flashes fine on my Samsung Galaxy S5 without error.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
boolean flashOn = false;
for (int i = 0; i < 20; i++) {
flashOn = !flashOn;
toggleFlash(flashOn);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
Wrapped in new Thread like others suggested here - better performance.
The app I'm making requires that a bit of code be executed whenever the value of a particular variable changes from 0 to 1.
The handler example below is the method I'm currently using to do this (I copied it from someone else).
I have a feeling it's not a proper method though because having just three of these handlers in my app causes the UI to be fairly unresponsive, and causes the device (a phone) to become quite hot.
As you can see, I've put 10ms delays in the handlers to try to deal with this.
Isn't there something more like OnClickListener that can listen at all times for a variable value change without putting such stress on the CPU?
I'm pretty new to Java and Android so a simple example would be very much appreciated.
final Handler myHandler1 = new Handler();
new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
try
{
Thread.sleep(10);
myHandler1.post(new Runnable()
{
#Override
public void run()
{
if (myVariable == 1)
{
myVariable = 0;
//do stuff
}
}
});
} catch (Exception e) {}
}
}
}).start();
You must set your variable via a setter method. Then, you can be reactive to that change.
public void setMyVariable(int value) {
this.myVariable = value;
if (myVariable == 1) {
doSomethingWhen1();
} else if (myVariable == 0) {
doSomethingWhen0();
}
}
A more elegant way to do that will be an observer pattern, Here you can find more detailed documentation about it.
You must certainly avoid while(true) loops on mobile device, it will drain your battery and you are also blocking the UI thread. That's the reason why your UI is unresponsive and your cellphone it's quite hot.
I am making a board game. The board doesn't ever move, but pieces on top of it sometimes do depending on user interaction. There are also UI elements which may update periodically.
Right now the way I set it up is by overwriting the onDraw() method of a SurfaceView subclass. I have a drawing thread that constantly calls postInvalidate() in a while loop:
class PanelThread extends Thread
{
//...
long sleepTime = 0;
long nextGameTick = System.currentTimeMillis();
#Override
public void run()
{
Canvas c;
while (_run)
{ // When setRunning(false) occurs, _run is
c = null; // set to false and loop ends, stopping thread
try
{
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder)
{
// Insert methods to modify positions of items in onDraw()
_panel.postInvalidate();
}
} finally
{
if (c != null)
{
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
nextGameTick += MILLISECONDS_PER_FRAME;
sleepTime = nextGameTick - System.currentTimeMillis();
if(sleepTime >= 0)
{
try
{
sleep(sleepTime, 0);
} catch (InterruptedException e)
{
continue;
}
}
else
{
//we're behind, oh well.
System.out.println("behind!");
nextGameTick = System.currentTimeMillis();
}
}
}
This is not efficient and is taking a lot of CPU. Is there a easy way to get android to only update when something changes?
You have the right idea, but it needs a bit of refinement.
You definitely do not want to loop as fast as the CPU can handle it though.
You should be sleeping your Thread in every loop for a little while. You most certainly do not need to do everything in your loop every millisecond.
I found this guide to FPS control to be incredible helpful in designing a game loop.
This Android-specific game loop guide also provides a lot of great sample code and an in-depth explanation.