FragmentTransaction animation: onAnimationEnd is called before it really ended - android

My question is very similar to this question, except that I need it to work with fragments instead of Views.
As explained in that thread, there seems to be a bug(?) in Android when an AnimationListener is attached to an Animation, which results in the onAnimationEnd() callback getting called before the animation has really completely ended.
I'm using fullscreen fragments which are animated in the FragmentTransaction (v4 support library) to have a horizontal "roll-in" effect. This works smoothly everywhere except in the fragment where I start a camera preview. Therefore I want to only start the camera preview once the animation is finished.
I tried using this method in my Fragment:
#Override
public Animation onCreateAnimation(final int transit,final boolean enter,final int nextAnim)
{
Animation anim=super.onCreateAnimation(transit, enter, nextAnim);
if (anim==null && nextAnim!=0)
anim=AnimationUtils.loadAnimation(getActivity(), nextAnim);
if(anim!=null)
{
anim.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation)
{
}
#Override
public void onAnimationRepeat(Animation animation)
{
}
#Override
public void onAnimationEnd(Animation animation)
{
scannerView.startCameraInHandlerThread();
}
});
}
Unfortunately starting the camera is quite an expensive operation and so my animation lags every time right before the animation is over. It looks ugly and my client is complaining about it.
I also thought about a cheap solution like waiting/sleeping on the camera thread, but the main thread actually needs to wait for the camera starting thread for synchronization otherwise it can deadlock in some cases, so sleeping actually makes the issue worse (the lag becomes longer).
Does anyone know how to solve this?
edit: someone asked for more code...
public void startCameraInHandlerThread()
{
if (mThread == null)
mThread = new CameraHandlerThread();
synchronized (mThread) {
mThread.openCamera();
}
}
private class CameraHandlerThread extends HandlerThread
{
Handler mHandler = null;
CameraHandlerThread()
{
super("CameraHandlerThread");
start();
mHandler = new Handler(getLooper());
}
synchronized void notifyCameraActionCompleted() {
notify();
}
void openCamera()
{
mHandler.post(new Runnable() {
#Override
public void run() {
startCamera();
notifyCameraActionCompleted();
}
});
try
{
wait();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
LOG.warn("Waiting for camera opening was interrupted");
}
}
}

I was able to come up with a workaround: Just delay the start of my method for a very short time to give the animation time to run to completion. On the devices that my client is going to use this works fine but I don't feel that it's a general enough solution, therefore I'm not going to mark this as the accepted answer.
#Override
public void onAnimationEnd(Animation animation)
{
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
scannerView.startCameraInHandlerThread();
}
}, 10); // will start after 10ms
}

Related

Weird problem with button clicking in a layout that has a RecyclerView

I have run into a very strange problem. There is a layout I have with a RecyclerView and a button that switches on animation. The point is if I click the button right after the app executes - say 10 seconds, everything is fine. But if I leave the app running idle for some seconds, without touching anything, then when I click the button again, the animation simply doesn't start at all. And yet if after that I slide RecyclerView about the screen with my finger (in any place!) then the animation triggers all of a sudden. As if it was somehow frozen and "woke up" only after I interacted with the RecyclerView. As if RecyclerView after some seconds puts its animation-related objects to sleep somehow and they "wake-up" only after the RecyclerView is slided?.. Apparently the listener "goes to bed"... Is there a way to keep the animation-related objects "awake" at all times?
Here is the Animation function:
private void recyclerViewAnimate(final RecyclerView recyclerView, LayoutAnimationController controller) {
if(isAnimating){
return;
}
controller = AnimationUtils.loadLayoutAnimation(recyclerView.getContext(), R.anim.layout_recycleview_disappear);
recyclerView.setLayoutAnimation(controller);
recyclerView.setLayoutAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation) {
isAnimating = true;
bt_add.animate().rotationXBy(180).setDuration(400).start();
addButtonLayout.animate().setDuration(400).alpha(0).withEndAction(new Runnable() {
#Override
public void run() {
addButtonLayout.setVisibility(View.INVISIBLE);
}
});
}
public void onAnimationRepeat(Animation animation) {}
public void onAnimationEnd(Animation animation) {
recyclerView.setVisibility(View.GONE);
layoutSettings.setVisibility(View.VISIBLE);
layoutSettings.animate().scaleX(0.95f).setDuration(0).withEndAction(new Runnable() {
#Override
public void run() {
layoutSettings.animate().alpha(1)
.scaleY(1.01f).scaleX(1f).setDuration(400).withEndAction(new Runnable() {
#Override
public void run() {
settingsText.animate().setDuration(300).alpha(1).start();
isAnimating = false;
recyclerView.setLayoutAnimationListener(null);
}
}).start();
}
}).start();
}
});
recyclerView.scheduleLayoutAnimation();
}
Instead of setting scheduleLayoutAnimation(); I needed to use startLayoutAnimation();

Stop AnimatedVectorDrawable animation after playing

I have an AnimatedVectorDrawable that animates from play to pause state when clicked.
...
animatedVectorDrawable.registerAnimationCallback(new Animatable2.AnimationCallback() {
#Override
public void onAnimationEnd(Drawable drawable) {
//Reset the image back to its original state
//What I've tried so far
/* img.setImageResource(R.drawable.original_state)
animatedVectorDrawable.stop()
animatedVectorDrawable.reset() */
}
});
animatedVectorDrawable.start();
However, I've not been able to successfully get it back to its original state so that I can play it back again. How can I solve this?
You could do like this:
final Handler mainHandler = new Handler(Looper.getMainLooper());
animatedVector.registerAnimationCallback(new Animatable2.AnimationCallback() {
#Override
public void onAnimationEnd(final Drawable drawable) {
mainHandler.post(new Runnable() {
#Override
public void run() {
animatedVectorDrawable.start();
}
});
}
});
animatedVectorDrawable.start();
To get the initial state of the drawable use animatedVectorDrawable.seekTo(0) and the you can call animatedVectorDrawable.stop()

Android Animation Lags (what's the difference between two methods)

I want to animate a movement of images.
I have two different implementations, the first involves two methods and runs smoothly, the other only needs one method and lags. I'd rather use the second one but can't figure out what causes the lags.
I don't think it's the code that calculates the new positions since it's very simple and in both methods almost the same (I removed it for better readability)
Here is the first:
public void animateCircleMovement(final long duration) {
// ...
post(new Runnable() {
#Override
public void run() {
animateStep();
}
});
}
public void animateStep() {
// ...
invalidate();
if(curTime<endTime) {
post(new Runnable() {
#Override
public void run() {
animateStep();
}
});
}
}
Here is the second
// ...
new Thread(new Runnable() {
#Override
public void run() {
while(currTime<endTime){
// ...
postInvalidate();
}
}).start();
Why does the second implementation cause lags?
Edited the postInvalidate() method
The animation runs smoothly if Thread.Sleep(10) is put into the while-loop.

Android animation for 1 second

I am trying to make a page where when the user leaves the page, there will be an animation (eg.: button will slide out) in the page and after that, the user will be sendt to a different activity.
No issue with the animation, but as the code for starting the new activity is written just after the animation code, the animation is not completing for 1 second (as I have set).
I want to execute the animation for 1 second first and then move to another activity.
Please help me.
Use AnimationListener.
private Animation.AnimationListener animListener = new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
// write code to start new activity.
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
};
Assign above listener to your animation
animation.setAnimationListener(animListener);
//Startanimation
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
// call Activity
// End animation
}
}, 1000);

Android ProgressBar: loading with Timer

Update:
This post was from when I was learning android with android 2.2, be sure to check if this is compatible with the api level you are working with.
Done alot of looking around for how to load progress bar with a timer, I've tried to use methods posted but always would get a pointer exception and or the testing app would crash at start up.
my question is, lol has anyone ran across any tutorials or examples on how to do this? I'm thinking all i need is a while loop but haven't seen that done on a timer yet. I'm a complete noob but am slowly but surely learning
My Timer
final Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
d.dismiss(); //MY DIALOG WINDOW
t.cancel();
}
}, 7000);
this is one i have tried to get to work but think i have done more damage then good with it
isRunning = false;
// handler for the background updating
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
total = total - 1;
String perc = String.valueOf(total).toString();
a.setText(perc + " SECONDS until close");
bar.incrementProgressBy(25);
}
};
super.onStart();
// reset the bar to the default value of 0
bar.setProgress(0);
// create a thread for updating the progress bar
Thread background = new Thread(new Runnable() {
public void run() {
try {
for (int i = 4; i < 20 && isRunning; i++) {
// wait 1000ms between each update
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
} catch (Throwable t) {
}
}
});
isRunning = true;
// start the background thread
background.start();
hoping someone might be able to shed some light on this for me,, as always sorry for the short generic question, just looking to find out how to load progress bar with timer
tahnks again for any and all help
Use a android.os.CountDownTimer
countDownTimer = new CountDownTimer(length_in_milliseconds,period_in_milliseconds) {
private boolean warned = false;
#Override
public void onTick(long millisUntilFinished_) {
progressBar.progress = (length_in_milliseconds-millisUntilFinished_)/lenght_in_milliseconds*100.0;
}
#Override
public void onFinish() {
// do whatever when the bar is full
}
}.start();
My answer from here:
You could use an ObjectAnimator to animate the progress of the ProgressBar:
ObjectAnimator animation = ObjectAnimator.ofInt(pb, "progress", 0, 100);
animation.setDuration(5000);
animation.setInterpolator(new DecelerateInterpolator());
animation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) { }
#Override
public void onAnimationEnd(Animator animator) {
//do something when the countdown is complete
}
#Override
public void onAnimationCancel(Animator animator) { }
#Override
public void onAnimationRepeat(Animator animator) { }
});
animation.start();

Categories

Resources