I am creating an app based on the Towers of Hanoi that includes an animation for each move, all less than one second long. I have one option where you can solve the puzzle manually and one where the program solves the puzzle itself, showing all of the animations. My issue occurs when the program tries to solve the puzzle itself. I've been trying to use handler.postDelayed within the recursive method that the puzzle uses to give each animation time to finish before attempting to start the next one:
int autoSolveCount = 0;
public void playHanoi(int n, String from , String other, String to) {
Handler handler = new Handler();
if (n == 0)
{
autoSolveCount++;
return;
}
if (n > 0){
playHanoi(n-1, from, to, other);
image.get(from).performClick();
image.get(to).performClick();
handler.postDelayed(new RunAutoSolve(n-1, other, from, to), 1000*(autoSolveCount+1));
}
}
public class RunAutoSolve implements Runnable{
int num;
String other = "";
String from = "";
String to = "";
public RunAutoSolve(int n, String o, String f, String t){
num = n;
other = o;
from = f;
to = t;
}
#Override
public void run(){
playHanoi(num, other, from, to);
}
}
image.get(to) and image.get(from) return a clickable ImageView for the tower being targeted. When they are clicked, other methods run the proper animation. When I solve the puzzle manually, I run into no issues, so I doubt it's a problem with the clickable images or the animations. The problem seems to be that the program doesn't have enough time to finish executing the first animation before beginning the second. The way my methods are set up, it will crash if an animation tries to start before the other one is finished. (This is not an issue during a manual execution.) When I run the program, there is a long pause before the first animation, and it crashes right after that animation is complete. So, is this a problem with where I place the delay, the timing, or something else? If you need to see more of my code, just ask. Thanks in advance!
Related
I'm suffering from a delay when starting an activity in my android application project.
Whenever a menu item or a clickable view is clicked, the onClickListener just creates a new Intent and starts specified activity. That's OK so far. But then, view is frozen for a noticeable time(around 1 sec) until user see the new activity.
That time may be caused by progress inside onCreate, but I measured time by System.currentTimeMillis() and printed it in logcat at the end. So it seems it takes only 20-30 ms and the log is printed long before user sees the activity.
Here is my code:
public class ExampleActivity extends MyActivity {
MyModel myModel;
long startTime;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startTime = System.currentTimeMillis();
setContentView(R.layout.activity_ders_programi);
setToolbar();
myModel = Controller.getMyModel();
if(myModel == null) { //If we don't have the object previously
//this fills the object, takes some time
myModel = new MyModel(this);
//myModel is observable and this activity is observer.
//Whenever it's done, it notifies this activity
}
else //If we got the object previously
createCardViews();
Controller.setMyModel(myModel);
setParentActivity();
}
//If Observable object notifies this activity, update() is called.
#Override
public void update(Observable observable, Object o) {
createCardViews();
}
//Creating a list of cardViews, this also takes some time
private void createCardViews() {
ArrayList<Card> cards = new ArrayList<Card>();
for(int i = 0; i < 5; i++) {
MyModelCardModel card = new MyModelCardModel(this, i);
card.init();
cards.add(card);
}
CardArrayAdapter mCardArrayAdapter = new CardArrayAdapter(this,cards);
CardListView listView = (CardListView) findViewById(R.id.my_card_list_view);
if (listView!=null)
listView.setAdapter(mCardArrayAdapter);
//I think here is the last point.
//After this point there will be no significant process.
long stopTime = System.currentTimeMillis();
Log.d("modelflow", "card create takes: " + (stopTime - startTime) + "ms");
}
So what am I doing wrong? If the delay is because the progress is heavy, then why the measured time seems little. Let's say progress causes delay, why don't application wait after showing the activity? And how to avoid this?
There is a project to test native apps performance in comparison to polymer+xwalk. You can find sources here https://github.com/collabora/xw-perf
this project proves that native apps perform much better but the delay for start activity and GC is noticeable. Also it is interesting to see how GC causes fps drops.
Your issue is either with Controller.SetMyModel() or setParentActivity().
Why do I narrow it down to those?
You time everything but those two calls.
Everything timed seems to run quickly.
There is no source code for either of those un-timed calls.
Those calls don't appear to be to Android methods with known behavior.
Given your description of Controller.SetMyModel() as being
Actually nothing more than a basic setter
the most likely candidate is setParentActivity(). You should post its source code.
I think this is not an easy question.
I'll be brief and give a little example of what is happening.
Let's say we have a source of data in file Byron.txt:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
And all that 's best of dark and bright
Meet in her aspect and her eyes:
Thus mellow'd to that tender light
Which heaven to gaudy day denies.
And this code execute inside an AsyncTask:
final ArrayList<Record> poem = new ArrayList<Record>();
final Object objectLock = new Object();
private Record rec = new Record();
#Override
protected Void doInBackground(Void... args) {
String line = null;
int i;
int last;
try {
process = Runtime.getRuntime().exec("cat Byron.txt");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 8192);
synchronized (objectLock) {
poem.clear();
last = i = poem.size() - 1;
}
while(line = bufferedReader.readLine()) != null) {
rec.setString(line);
synchronized (objectLock) {
last++;
poem.add(last, rec);
}
while(!bPause && i < last) {
i++;
publishProgress(poem.get(i));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected synchronized void onProgressUpdate(Record... m) {
if(m.length > 0) {
mContext.mTable.appendRow(m[0]);
}
}
where there is a TableLayout in the UI and each time we get a new line we add a new TableRow to it.
And this is the output we see in the UI:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Thus mellow'd to that tender light
Thus mellow'd to that tender light
And we go into the debugger and we see why it happens.
Sometimes the synchronized (objectLock) is skipped and the loop continues.
There is no publishing because i already catched last.
Later the block is executed as many times as it was skipped,
, but the original line is lost and the current line is added instead to poem several times
Then, all the new lines are published until i catches last again.
So you see that I followed the code and I can explain what's happening, the question here is: Why the block is skipped?, Why?
I expected the synchronized block to stall until it can be executed.
At least this how I understood the function of synchronized (objectLock)
even without using wait() and notify()
I don't pretend to open a discussion here (although if you want we can open one in the chat area)
If you see some fault in the code, then, answer the question to let me know.
NOTES:
synchronized is needed because somewhere else in the app, the user may want to email the lines he got so far.
The user may pause the publishing (bpause); that's the while loop and i follows last only when bPause is false.
I decided to publish the answer. Even though I feel very embarrassed by its simplicity.
I discovered it only after I had already dug deep into AsyncTask class and message handling and whatnot.
I publish it in hope it will help people to check the basic things before jumping to
conclusions, and that someone out there will save himself half a day debugging because of
this post.
The Record rec was the same one each time. The poem ArrayList had the same element id for each entry. And the content changed on all of them at once, since they were all the same.
When the progress was published immediately it printed the right string, the last one. But if some delay cause the progress to publish later, then retrieving the poem.get(i) records retrieved a different entry but with the same pointer, thus, the same content.
The solution was to create a new Record each loop.
Do the synchronization for last object.
synchronized (last) {
last++;
poem.add(last, line);
}
I have a little problem with ChangeableText in AndEngine. I want to know how to update it's text without freezing the screen? For now I'm using this way, but it's freezing my phone for maybe 2-3 seconds :
private void removeFace(final Sprite face) {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}
Any ideas how to do that?
Remember that when you detachChild you should do this in thread because if you don't it can causes errors. Use this construction
runOnUpdateThread(new Runnable(){
#Override
public void run() {
if(yourSprite.hasParent())
scene.detachChild(yourSprite);
}});
You can put there all code if you want then your phone shouldn't freez
private void removeFace(final Sprite face) {
runOnUpdateThread(new Runnable(){
#Override
public void run() {
hm = getIconNames();
if(face.getUserData().equals("petrol")){
elapsedText.setText(hm.get(25));
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(face);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(face);
this.mScene.detachChild(face);
} else {
}
System.gc();
}});
}
Thats probably because you are fetching some information while setting the text.
What you should do is, get your
String hm = hm.get(25); //What ever the correct object is or variable. im guessing its a string or int.
Then
pass it to the Changeable text to be set.
elapsedText.setText(hm); //If its a int make sure you do String.valueOf(hm);
The only 3 methods here that have the possibility to take long are getIconNames() and get(), and System.gc()
The others are usually methods that return immediately, or have a very low complexity. For example, getPhysicsConnectorManager() returns immediately. findPhysicsConnectorByShape, unregisterPhysicsConnector, unregisterTouchArea and detachChild all have complexity of O(n), (And most of the others methods also have complexity of O(1) or O(n)).
I recommend you to look in the LogCat and when System.gc() is called, you will see a Log.i (blue) message of the tag of dalvikvm which will begin with GC_EXPLICIT and will give you some information about how long did the garbage collection took, etc....
If that GC call isn't taking the time, it must be your 2 methods, getIconNames() and hm.get(). You can put a Log.d message after each code line, which will write the last code line executed. This way you can follow the times.
Im doing a little app, its a memory game, you choose one card, it turns up, you choose the second card, it turns up, if they are the same they are out of the game, if they dont match, they are turned down again.
I have
public class PlayActivity extends Activity implements OnClickListener.
The flip events are trigged by click handlers, declared at public void onCreate(Bundle savedInstanceState) they work fine.
When the first card is selected, it calls my method Action, this sets the image from default (the card back) to the 'real' image (the card front). Fine so far.
My problem is the second card: when its selected, it calls method Action, where it should set the front image (lets call it 'middle action'), then a litle pause (a while loop doing nothing until x milliseconds), and then it checks what to do (if they match or not) and turn them down or take the out of the game. You can see where is the problem: the screen only displays the result after x milliseconds (the 'middle action' is not being draw).
Since I have done some little games with XNA, I know the loop Update-Draw, so I know here im updating the same thing twice so always the last one is drawn. But here, the only updating I can have is when click events are trigged, I need a periodic, constant update.
Help?
You can probably use a TimerTask in order to handle that. You can implement it like the following.
This probably isn't the most robust way to do it, but it is an idea. If I figure out a better way to do it in a short time I'll edit my post. :)
Also I would like to add that if you want to make a game that uses an update / draw loop you may need to use a SurfaceView to draw your game. Look at the example here http://developer.android.com/resources/samples/JetBoy/index.html
public class TestGameActivity extends Activity {
/* UIHandler prevents exceptions from
performing UI logic on a non-UI thread */
private static final int MESSAGE_HIDE_CARD = 0;
private class UIHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_HIDE_CARD:
ImageView cardView = (ImageView) msg.obj;
cardView.setImageResource(R.drawable.faceDownCard);
break;
}
}
}
private UIHandler handler = new UIHandler();
// Handle my click. V is the card view
public void onClick(View v) {
final int viewID = v.getId();
// Create a hide task
TimerTask hideTask = new TimerTask() {
#Override
public void run() {
// Construct a message so you won't get an exception
Message msg = new Message();
msg.what = MESSAGE_HIDE_CARD;
msg.obj = findViewById(viewID);
handler.sendMessage(msg);
}
};
// Schedule the task for 2 seconds
new Timer().schedule(hideTask, 2000);
}
}
I'm making a game that displays some numbers on a canvas (score, time, etc).
The way that I currently do this is with the drawtext command on a canvas
// score is some int
draw(Canvas c) {
c.drawText(score+"", x, y, paintSyle);
}
I hear that object creation and garbage collection are expensive operations, and I think this is creating a new string every time it is called.
Right now my game with all bitmap drawing and everything jumps around from 25 to 60 fps. I'd like it to stay closer to the higher number and I'm trying to find ways to speed it up.
Would it be faster/better to make(or find?) some mutable subclass of string and work around this problem? Is there another way to solve this issue? Or is this just how it is?
Introduce two new private member variables String renderedScoreString and int rederedScore and rewrite your draw()-method like that:
draw(Canvas c) {
if (this.score != this.renderedScore || this.renderedScoreString == null) {
this.renderedScore = this.score;
this.renderedScoreString = Integer.toString(this.renderedScore);
}
c.drawText(this.renderedScore, x, y, paintStyle);
}
that should save you a lot! of object creations. You could also hide the boilerplate code behind a getter method, e.g. String getScoreString() which does the same, so you don't have it in the draw()-method.
A friend of mine tipped me in on a solution to this problem. When you want to draw something over time, one of the best (and simplest) mechanisms to do so is to split up what you need to do into two completely separate processes.
ie. Only use the draw command exclusively for drawing stuff, keep logic/assignment in Draw() to an absolute minimum.
private final long TIMER_PERIOD = 500;
private String timeString;
private Runnable updateRunnable;
private Handler updateHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
updateRunnable = new Runnable() {
#Override
public void run() {
timeString = GetTimeString();
updateHandler.postDelayed(updateRunnable, TIMER_PERIOD);
}
}
}
Draw(Canvas c) {
c.drawText(timeString, x, y, paintStyle);
}
In this example the Draw command simply takes timeString in its current state and draws it to the screen. This is highly efficient use of the draw function as it does not require any object creation, and no logic is present that is not immediately required for any drawing to occur. . In the background a Runnable is executing the run() function every 500 miliseconds (approximately). Simply update the Run() function with whatever logic you need to calculate the time (example has a dummy function GetTimeString())
I hope this is helpful.
I know I'm resurrecting a dead thread, but there is one extra optimisation you can add to this which restricts String creation to a one-time thing and thus only triggers the GC once at the start and not during the game (which is quite important for an android game).
Somewhere during the start of your game (onCreate, onResume, as part of a singleton during application startup, etc) create a large String[] which can hold the maximum score (my game fills an array of 10000, so the max score would be 9999). Then loop over it with a for loop, filling each index with a String.valueOf(i).
for (int i = 0; i <scoreStrings.length; i++)
{
scoreStrings[i] = String.valueOf(i);
}
Now, when you need to draw the score, just use the int you use to store the score in as an index to that array, and "hey, presto!", you get the correct string for your score.
canvas.drawText(scoreStrings[score], x, y, paint);