Animate android views in order - android

For a blackjack game I'm making, I need the card to translate to the dealer position from the pile, then to the player position, so I made a general method for it.
private void dealHand() {
animateCard(dealer_iv_1);
animateCard(dealer_iv_2);
animateCard(player_iv_1);
animateCard(player_iv_2);
}
private void animateCard(View v) {
animated_card_iv.animate().x(v.getX()).y(v.getY()).setDuration(1000).withEndAction(new Runnable() {
#Override
public void run() {
animated_card_iv.setX(pile_iv.getX());
animated_card_iv.setY(pile_iv.getY());
}
}).start();
}
As it's written right now it's obviously gonna animate only one card to player_iv_2.
I don't want to wait 1000 millis between animateCard() calls using a Timer or CountDownTimer.
What I would want is for it to be something like this:
private void dealHand() {
animateCard(dealer_iv_1).wait();
animateCard(dealer_iv_2).wait();
animateCard(player_iv_1).wait();
animateCard(player_iv_2);
}
so animateCard() needs to return a type and let me know when it's done. how is this possible?
So far this is what I got:
private void dealHand() {
animateCard(dealer_iv_1, 0);
animateCard(player_iv_1, 1010);
animateCard(player_iv_2, 2010);
}
private void animateCard(View v, long startDelay) {
final ImageView iv = new ImageView(this);
iv.setLayoutParams(new ViewGroup.LayoutParams(104, 149));
iv.setImageResource(R.drawable.back0);
iv.setX(pile_iv.getX());
iv.setY(pile_iv.getY());
((RelativeLayout)findViewById(R.id.pile_layout)).addView(iv);
iv.animate().x(v.getX()).y(v.getY()).setDuration(1000).setStartDelay(startDelay).withEndAction(new Runnable() {
#Override
public void run() {
((RelativeLayout)findViewById(R.id.pile_layout)).removeView(iv);
}
}).start();
}
As you can see I'm now creating 3 ImageViews every time dealHand() is called, and removing each of them after they finish animate, I just gotta ask if I'm doing it properly since I tried calling dealHand() about 50 times which produced 150 of ImageViews, I saw it took about 1.5Mb of RAM in the profiler, this 1.5Mb didn't clean up, even when I called System.gc().

First, ditch the animation library and use the ObjectAnimator library. It's newer and 100x more useful.
Then, use an AnimatorSet to play the animations. AnimatorSets can play animations either sequentially or in order. You can just create your animations and either use the AnimatorSet#Builter or the AnimatorSet#playSequentially to play them all in order.
Then, don't worry about the garbage collection and cleanup. Just remove them from View and the garbage collector will clean them up when it's ready. However, you may consider a more efficient strategy by recycling and re-using the ImageViews each time. That way you're not re-building them constantly. Also, it prevents a lot of heavy, unnecessary garbage collecting. This would only need to be considered if the animations happen frequently.

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.

Synchronizing UI update with PostDelayed()

I'm new to Android development, and running into a synchronization issue. I made a simple matching game where you flip two cards over at a time, and try to find matches. What I want to do is flip the previous two cards over if either:
The user clicks a new card (do it immediately)
After a certain amount of time, if the user does nothing
I tried to safeguard my "flipIfFlipped" routine by marking it synchronized, and checking to be sure that the card has not already been flipped back, but I still get this double-flipping behavior (my force flip must flip it first, then the timer flips it again, or vice versa).
Here's my method on my CardView (ImageView subclass):
public synchronized void flipIfFlipped() {
if (this.flipped) {
this.flip();
}
}
Here's my force flip at the top of my onItemClickListener, if we clicked a card while two are still up:
CardView lastCard = game.getLastCard();
if (null != lastCard){
lastCard.flipIfFlipped();
}
CardView secondLastCard = game.getSecondLastCard();
if(null != secondLastCard) {
secondLastCard.flipIfFlipped();
}
And here's my attempted delayed flip, later, if we just got mismatched cards:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
clickedImage.flipIfFlipped();
lastCard.flipIfFlipped();
}
}, 3000L);
Again, I'm a newbie, so I'm sure I'm probably missing something basic.

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 AndEngine - How can I update ChangeableText value

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.

How can I draw an animated view in android?

I created a custom view from scratch. Extended View and overrided onDraw().
When comes down in animating the view i generate a custom animation using offsets.
eg.
while(!isOnTop){
mOffset++;
//draw the component a a it higher using the offset
if(position == 0)
isOnTop==true;
invalidate();
}
The thinking is that my frames come from invalidate it self. The problem is that invalidation of this view can come just by scrolling a listview at the same screen.
This "shared invalidation()" causes lag to my animation.So is there a way out of that lag?
Do you have any other suggestion of performing animations in that shared enviroment?
Creating an animation using a seperate thread that calculates the offset also needs forced invalidation() calls to display the animation (correct me if i'm wrong).
Is the only solution to perform the animation in eg 10 invalidation requests with a larger step? It will ease the lag out but i think i can use a different approach on that.
"What is best" of course depends greatly on exactly what you are trying to do. You haven't said what you are trying to accomplish, so we can only guess at what may be best for you.
Here are some simple things:
If you want to animate bitmap frames, use AnimationDrawable: http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
If you want to animate the movement of views within your hierarchy, use the view animation framework: http://developer.android.com/guide/topics/graphics/view-animation.html
The new more general animation framework can do a lot more stuff an is often easier to use: http://developer.android.com/guide/topics/graphics/animation.html. This is natively available in Android 3.0+ but can also be used in Android API level 7 with the support v7 library.
If you want to write a custom widget that is an integrated part of its view hierarchy and manually does its own animation drawing, you can use a Handler to time the updates (usually you'll want 60fps or 20ms between each invalidate()) and then in your onDraw() method draw your view's state based on SystemClock.uptimeMillis() as a delta from when the animation started.
Here's a simple repeated invalidate using Handler:
long mAnimStartTime;
Handler mHandler = new Handler();
Runnable mTick = new Runnable() {
public void run() {
invalidate();
mHandler.postDelayed(this, 20); // 20ms == 60fps
}
}
void startAnimation() {
mAnimStartTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mTick);
mHandler.post(mTick);
}
void stopAnimation() {
mHandler.removeCallbacks(mTick);
}
Since this question has some interest I will reply.
The best way to to that is to have a separate canvas thread. A "separate" canvas can only be achieved with a SurfaceView. LunarLanding is an excelent example of that use. Each frame is calculated separately than the main view sharing only CPU time, not drawing time. Therefore is faster, even with the combination of for e.g a regular view at the top and an animating view at the bottom.
But you have to set an interval if you are in that shared environment. That interval is used for the FPS cap. If you don't set FPS cap then the CPU will running wild managing to get good animation to the SurfaceView if it was alone. Capping it at 60fps or even less will do the trick to draw all views efficiently with no CPU overload.
So see the drawing thread of the Lunar Landing from the API demos and set a FPS cap.
private long timeNow;
private long timeDelta;
private long timePrevFrame;
private void capFps(int fps) {
timeNow = System.currentTimeMillis();
timeDelta = timeNow - timePrevFrame;
try {
//ps you can always set 16 instead of 1000/fps for 60FPS to avoid the calculation every time
Thread.sleep((1000 / fps) - timeDelta);
} catch (InterruptedException e) {
}
timePrevFrame = System.currentTimeMillis();
}
and then the drawing thread will look something like this:
#Override
public void run() {
Canvas c;
while (run) {
c = null;
sleepFps(60, false);
try {
synchronized (surfaceHolder) {
c = surfaceHolder.lockCanvas(null);
widgetView.doDraw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}

Categories

Resources