Android AndEngine - How can I update ChangeableText value - android

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.

Related

Android piccaso callback return before load

i have an android mobile app and im trying to check if a specific LatLng is at water, so im using google static map api to get an image of the location, and then to check if the image is blue.
im using this code -
private boolean result;
public boolean IsWater(LatLng position)
{
imageView = (ImageView) this.findViewById(R.id.imageView);
checkText= (TextView) this.findViewById(R.id.checkText);
String lati = Double.toString(position.latitude);
String longi = Double.toString(position.longitude);
String url = "http://maps.googleapis.com/maps/api/staticmap?center="+lati+"," + longi + "&zoom=20&size=1x1&style=element:labels%7Cvisibility:off&style=element:geometry.stroke%7Cvisibility:off";
Picasso.with(MainActivity.this).load(url)
.into(imageView, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(0, 0);
int blueValue = Color.blue(pixel);
if(blueValue>250)
result =true;
}
#Override
public void onError() {
result =false;
}
});
return result;
}
the problem, i think, is that it is not synchronized, and IsWater get to the last line and return a null for result before the onSuccess kicks in...
any thoughts?
Picasso loads images on a background thread by default. The operation you are running is asynchronous. Therefore, it does not block your method from returning result before the onSuccess callback has been called.
The problem is Picasso is running Async. within the calling method "isWater", so what ends up happening is the method will return 'false' because instead of waiting on Picasso to finish because it isn't in serial execution. This is due to the function call's stack frame being popped off the stack once it reaches the return statement.
What you need to do is the following by using a Target.
// make sure to set Target as strong reference
private Target loadtarget;
public void loadBitmap(String url) {
if (loadtarget == null){
loadtarget = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// do something with the Bitmap
handleLoadedBitmap(bitmap);
}
#Override
public void onBitmapFailed() {
}
};
}
Picasso.with(this).load(url).into(loadtarget);
}
public void handleLoadedBitmap(Bitmap b) {
// do something here
}
This code was taken from here, and should offer you some insight on how to get it work for your goal.
A Target is essentially an object that holds the bitmap you need so it is still in memory. Generally used for custom view objects though as a field. Here is documentation Target docs
Asynchronous execution is one of the hardest things to wrap ones head (and subsequently ones code) around. In all of the JavaScript frameworks I've used, the network communication is done in a background thread. The intended effect is that the User Interface thread is left free to keep the user from thinking that things locked up. Mouse-overs and tool-tips will all still work, while a background thread is dragging data out of a slow server.
The code patterns, on the other hand, aren't as nicely shaped.
My problem is/was still basically thinking linearly, or functionally, instead of embracing the event-driven nature of modern JavaScript: Passing a function to an asynchronous method to completely handle that response. Not just return a value, but perform the full task that the value was needed for. The callback can call the other functions to assist with that task, and may be able to fill in a cache (of whatever sort) so that other functions that may need this data do not necessarily have to wait for another response. This often (to me) feels backwards from the logic pattern I was following to solve the original purpose of the code.
I've stumbled on this pattern-flip many times, coming from C/C++ as my first programming language. It can sometimes help to avoid the anonymous function pattern of callback definition and define one's callback functions with names, then pass the name to the asynchronous call, but that is extra steps and extra memory use in the long run. The big hurdle is thinking in terms of Event and EventHandler, versus function and data.
I hope this helps a little.

Android Handler.postDelayed use in Recursion

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!

Hide custom search bar if all items in adapter are showing

The problem I have is that listView.getLastVisiblePosition always returns -1 so I can't hide the searchView. I check this right after setting the adapter and anywhere I have tried to put this it still returns -1. I didn't see in the Docs why this would be but I imagine it would return -1 if the ListView is not showing any items. However, listView.getFirstVisiblePosition() returns 0 always, even when there is more than one item showing.
I have tried both methods Here but it doesn't make a difference when getting the wrong value.
#SuppressLint("NewApi") private void setFilters(String curType, Object curFilter)
{
// initialize several lists
itemsAdapter = new ArrayAdapter<Rowdata>(this, R.layout.list_item_text, foodItems);
listView.setAdapter(itemsAdapter);
int numItems = listView.getLastVisiblePosition() - listView.getFirstVisiblePosition();
if (numItems > foodItems.length)
{ searchField.setVisibility(View.GONE); }
else
{ searchField.setVisibility(View.VISIBLE); }
}
This method is called any time a Button is pressed or text is changed that can filter through the list. So the question is why would listView.getLastVisiblePosition() always return -1 and why would listView.getFirstVisiblePosition() always return 0? No errors/exceptions, everything runs fine except for not getting the expected results. Note: itemsAdapter.getCount() returns the correct value.
Also, I have to support API >=10
Edit
If anyone needs clarification, let me know. But basically, I have an EditText I use to search through the list. I want to hide this when there aren't more items in the list than what fit on the screen. listView.getLastVisiblePosition() always returns -1
I would really like to know the cause of the original problem but if anyone has any better way of hiding the search box when items all fit on the screen, I am open to suggestions.
Update
I put a breakpoint in onItemClick() and there I get the correct values for getFirstVisiblePosition(), getLastVisiblePosition(), and listView.getChildCount(). Before this, I get 0, -1, and null respectively.
What you need to do is roughly
listview.post(new Runnable() {
public void run() {
listview.getLastVisiblePosition();
}
});
Why this way and not directly?
Android apps run in a big event loop known as the UI / main thread. Everything that is executed in there is the result of some event. For example when your Activity needs to be created that's some sort of Activity creation event. The loop will execute code that handles this event and will for example once your are considered "created" call the onCreate method. It might call more than one method within the same iteration but that's not really important.
When you setup things like the UI in any of those onSomething methods nothing is actually drawn directly. All you do is set some state variables like a new Adapter. Once you return from those on methods the system gains back control and will check what it needs to do next.
The system will for example check if the window needs to be redrawn and if so will enqueue a redraw event in the event queue which is at a later point executed by the loop. If nothing needs to be drawn it's just idle and will wait for example for touch events that are enqueued for that loop as well.
Back to your problem: By calling .setAdapter() you essentially reset all states of the ListView. And since actual updates of the ListView will only happen after you hand control back to the system you will get nothing useful out of .getLastVisiblePosition().
What needs to happen before is that ListView is instructed to be redrawn or to measure it's new size, count the amount of items it has and so on. Once it has done that it will be able to give you the required information.
.post(Runnable r) simply enqueues a Runnable into the eventqueue which is then executed by the loop once it's first in the queue.
a Runnable does not require a Thread, it's just a regular Object with a method named run() and the contract of a Runnable is simply that something (which often happens to be a Thread) can call the run() method to execute whatever you want to run. Magical loop does that.
Result of you posting a runnable is looks inn pseudo code somewhat like this:
void loop() {
yourActivity.onSomething() { loop.enqueue(runnable) }
ListView.redraw() // |
runnable.run() // <--+
}
My suggestion to resolve this problem will not be professional or light weight.
I am suggesting that you should get count of all views in listView and check every one of them are they visible.
example:
private int getIndexOfLastVisibleView(ListView view){
int count = view.getChildCount()-1;
for(int i = count ; i>=0 ; i--){
View checkedView = view.getChildAt(i);
if(checkedView.isShown()){
return i;
}
}
return -1;
}
May not be perfect but I hope that it will work.
You can refer to my answer here Strange problem with broadcast receiver in Android not exactly the same but you can get the idea why your code not working.
To make it more clear, when you set the adapter to the ListView, nothing has been drawn yet and the method getLastVisiblePosition() can only return the correct value after the listview finish drawing all of it's visible children and know which one is the last visible one.
So, the most appropriate approach I can suggest here is trigger a callback after the listView finished drawing and we get the correct value then.
The ListView with listener after drawing:
static class MyListView extends ListView {
private OnDrawCompletedListener mOnDrawCompletedListener;
public MyListView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mOnDrawCompletedListener != null) {
mOnDrawCompletedListener.onDrawCompleted();
}
}
public void setOnDrawCompletedListener(OnDrawCompletedListener listener) {
mOnDrawCompletedListener = listener;
}
public static interface OnDrawCompletedListener {
public void onDrawCompleted();
}
}
The sample code for getting last visible position
mListView.setAdapter(new EfficientAdapter(this));
//Will get -1 here
Log.e("Question-17953268",
"getLastVisiblePosition = "
+ mListView.getLastVisiblePosition());
mListView.setOnDrawCompletedListener(new OnDrawCompletedListener() {
#Override
public void onDrawCompleted() {
//Will get correct value here
Log.e("Question-17953268",
"getLastVisiblePosition = "
+ mListView.getLastVisiblePosition());
}
});
Thanks to zapl's answer I was able to get what I needed. I thought I would post the full code in case it helps anyone
listView.post(new Runnable()
{
public void run()
{
int numItemsVisible = listView.getLastVisiblePosition() -
listView.getFirstVisiblePosition();
if (itemsAdapter.getCount() - 1 > numItemsVisible)
{ searchField.setVisibility(View.VISIBLE); }
else
{
searchField.setVisibility(View.GONE);
setFilters("searchtext", "");
}
}
});

Draw on a canvas with delay - "make onDraw() slow down"

I use functions for canvas like drawCircle and drawPoint in android.
This works fine.
But the problem now is to draw these different items with a delay, so it looks like an animation.
What kind of mechanism should I use? Have tried with async but I dont like that way of doing it.
Should I use some kind of timer that just draw with an interval or is there other clever ways to do this?
I use this strategy, first I declare a Handler and a Runnable that way:
private final Observable mObservable = new Observable();
private final static int TIME_STEP_MS = 5;
private final Handler mHandler = new Handler();
private final Runnable mTimeManager = new Runnable()
{
public void run()
{
mObservable.notifyObservers(TIME_STEP_MS);
mHandler.postDelayed(mTimeManager, TIME_STEP_MS);
}
};
Then when I want to start my time manager I just call the mTimeManager.run() and it will start to notify my Observer s (previously added) periodically.
If you need for some reason stop the timer or something you just do that:
mHandler.removeCallbacks(mTimeManager);
[ EDIT - More complete code ]
Ok than let's make it clearer, first I made a custom Observable object like that [that's optional]:
private final Observable mObservable = new Observable()
{
public void notifyObservers()
{
setChanged();
super.notifyObservers();
};
#Override
public void notifyObservers(Object data)
{
setChanged();
super.notifyObservers(data);
};
};
the reason for that is just because I can't call setChanged() outside Observable class - it's protected, if it's not changed it doesn't notify any observer.
The other declarations keep the same as shown before, now I need to start this TimeManager somewhere, my app is a LiveWallpaper and I make all rendering stuff into a class that extends a Thread but you don't need that necessarily, I made a method called resumeDrawing(), this one is called right after super.start(); at my #Override of public synchronized void start() from Thread class, the method looks like that:
public void resumeDrawing()
{
if (!mTimeManagerRunning) // just a boolean field in my class
{
System.err.println("Resuming renderer."); // just for debug
mTimeManager.run();
mTimeManagerRunning = true;
}
else
{
System.err.println("Renderer already running."); // just for debug
}
}
and it's dual:
public void pauseDrawing()
{
if (mTimeManagerRunning)
{
System.err.println("Pausing renderer.");
mHandler.removeCallbacks(mTimeManager);
mTimeManagerRunning = false;
}
else
{
System.err.println("Renderer already paused.");
}
}
Ok, now we can start and stop the time manager, but who's listening? Nobody! so let's add'em: On the constructor of my Renderer I add some Observer s to my mObservable object, one of those is the Renderer itself, so my renderer extends Thread and implements Observer:
#Override // from Observer interface
public void update(Observable arg0, Object arg1)
{
mElapsedMsRedraw += (Integer) arg1;
if (mElapsedMsRedraw >= mDrawingMsPerFrame)
{
mElapsedMsRedraw = 0;
drawEm(); // refresh the canvas and stuff
}
}
to add observers you simply do mObservable.addObserver(THE_OBJECT - Implements Observer)
you can see that I don't re-render my stuff each time I'm notified, that's because I use this TimeManager for other thinks than just refresh the Canvas like updating the position of the objects I want to draw just internally.
So, what you need to slow down the drawing is to change the way your objects change internally while the time passes, I mean your circles and points etc, or you can chance your time step, I recommend the first one.
Was it clearer? I hope it helps.
I would use a timer, or create Animations. You can create Animations that will do all sorts of things including changing transparency over time.
Here's the Android Documentation for Animation Resources
I believe there may be sophisticated ways of doing this, but for my needs I used a simple method that has a lot of advantages:
I first create records of coordinates (and any other data needed) for every point of the drawing -- instead of drawing the points on the spot -- and then reproduce them using a timer (Android handler, preferably). This also offers a lot of possibilities while actual drawing: pause, go faster/slower, go backwards, ...
I don't know if this method can be used for complicated drawings, but it is fine for drawing shapes, curves, surfaces, etc.

Android : Displaying score as a string on canvas is creating a new string per draw command. How do I get around this?

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);

Categories

Resources